Compare commits
186 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b01d3e894b | |||
| 13dc6a0e32 | |||
| 96714550d0 | |||
| 2b6c751f55 | |||
| 08d3a2a03a | |||
| a79ca78781 | |||
| e08333dba1 | |||
| 8705dd1df5 | |||
| 7b4da9d422 | |||
| e51b2fe2f3 | |||
| f8b4ce103f | |||
| e82b4b8817 | |||
| 36e9df82b0 | |||
| cbce9af00b | |||
| 4a4304d65f | |||
| edad5306f2 | |||
| 5b775dfec9 | |||
| a485652ca5 | |||
| ed308246d7 | |||
| 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 |
@@ -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'
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,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,12 +1,15 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="pl">
|
<html lang="pl">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
|
||||||
|
|
||||||
<meta name="keywords" content="Stacjownik, TD2, Train Driver 2, stacjownik-td2" />
|
<meta
|
||||||
<meta name="description" content="Automatycznie odświeżana strona wyświetlająca stacje w Train Driver 2!" />
|
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>
|
<title>Stacjownik</title>
|
||||||
|
|
||||||
@@ -16,15 +19,42 @@
|
|||||||
<link rel="manifest" href="/site.webmanifest" />
|
<link rel="manifest" href="/site.webmanifest" />
|
||||||
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5" />
|
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5" />
|
||||||
<meta name="msapplication-TileColor" content="#da532c" />
|
<meta name="msapplication-TileColor" content="#da532c" />
|
||||||
<meta name="theme-color" content="#ffffff" />
|
<meta name="theme-color" content="#222222" />
|
||||||
|
|
||||||
<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 rel="icon" href="favicon.ico" />
|
||||||
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Quicksand:wght@400;500;700&display=swap" rel="stylesheet" />
|
<!-- 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>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -1,33 +1,44 @@
|
|||||||
{
|
{
|
||||||
"name": "stacjownik",
|
"name": "stacjownik",
|
||||||
"version": "1.11.1",
|
"version": "1.18.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "vue-tsc --noEmit && vite build",
|
"build": "vue-tsc --noEmit && vite build",
|
||||||
"deploy": "yarn build && firebase deploy --only hosting",
|
"deploy": "yarn build && firebase deploy --only hosting",
|
||||||
"preview": "yarn build && vite preview"
|
"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": "^16.0.3",
|
"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",
|
||||||
"sass": "^1.53.0",
|
"sass": "^1.67.0",
|
||||||
"socket.io-client": "^4.4.1",
|
"socket.io-client": "^4.7.2",
|
||||||
"vue": "^3.2.37",
|
"vue": "^3.3.4",
|
||||||
"vue-i18n": "^9.1.6",
|
"vue-i18n": "^9.4.1",
|
||||||
"vue-router": "^4.0.0-0"
|
"vue-router": "^4.2.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^18.11.17",
|
"@types/node": "^20.6.2",
|
||||||
"@vitejs/plugin-vue": "^4.0.0",
|
"@vite-pwa/assets-generator": "^0.0.10",
|
||||||
"axios": "^1.2.1",
|
"@vitejs/plugin-vue": "^4.3.4",
|
||||||
"typescript": "^4.9.4",
|
"axios": "^1.5.0",
|
||||||
"vite": "^4.0.3",
|
"prettier": "^3.0.3",
|
||||||
"vite-plugin-pwa": "^0.14.0",
|
"typescript": "^5.2.2",
|
||||||
"vue-tsc": "^1.0.18"
|
"vite": "^4.4.9",
|
||||||
|
"vite-plugin-pwa": "^0.16.5",
|
||||||
|
"vue-tsc": "^1.8.11",
|
||||||
|
"@vue/eslint-config-prettier": "^8.0.0",
|
||||||
|
"@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%",
|
||||||
|
|||||||
|
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 |
|
Before Width: | Height: | Size: 546 B 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 |
|
Before Width: | Height: | Size: 9.2 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 799 B |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 4.2 KiB |
@@ -1,3 +0,0 @@
|
|||||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="M8.00251 14.9297L0 1.07422H6.14651L8.00251 4.27503L9.84583 1.07422H16L8.00251 14.9297Z" fill="black"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 215 B |
@@ -1,97 +1,99 @@
|
|||||||
@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 {
|
||||||
.modal-anim {
|
&-enter-active,
|
||||||
&-enter-active,
|
&-leave-active {
|
||||||
&-leave-active {
|
transition: all $animDuration $animType;
|
||||||
transition: all $animDuration $animType;
|
}
|
||||||
}
|
|
||||||
|
&-enter-from,
|
||||||
&-enter-from,
|
&-leave-to {
|
||||||
&-leave-to {
|
transform: translateY(-25%);
|
||||||
transform: translateY(-25%);
|
opacity: 0;
|
||||||
opacity: 0;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
.route {
|
||||||
.route {
|
margin: 0 0.2em;
|
||||||
margin: 0 0.2em;
|
|
||||||
|
&-active,
|
||||||
&-active,
|
&[data-active='true'] {
|
||||||
&[data-active='true'] {
|
color: $accentCol;
|
||||||
color: $accentCol;
|
font-weight: bold;
|
||||||
font-weight: bold;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// APP
|
||||||
// APP
|
#app {
|
||||||
#app {
|
color: white;
|
||||||
color: white;
|
font-size: 1rem;
|
||||||
font-size: 1rem;
|
overflow-x: hidden;
|
||||||
|
|
||||||
@include smallScreen() {
|
@include smallScreen() {
|
||||||
font-size: calc(0.5rem + 1.3vw);
|
font-size: calc(0.65rem + 0.8vw);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@include screenLandscape() {
|
||||||
// CONTAINER
|
font-size: calc(0.45rem + 0.8vw);
|
||||||
.app_container {
|
}
|
||||||
display: flex;
|
}
|
||||||
flex-flow: column;
|
|
||||||
|
// CONTAINER
|
||||||
min-height: 100vh;
|
.app_container {
|
||||||
|
// display: flex;
|
||||||
header {
|
// flex-flow: column;
|
||||||
flex: 0 0 auto;
|
display: grid;
|
||||||
}
|
grid-template-rows: auto 1fr auto;
|
||||||
|
grid-template-columns: 100%;
|
||||||
main {
|
|
||||||
flex: 1 1 auto;
|
min-height: 100vh;
|
||||||
|
}
|
||||||
padding: 0 0.5em;
|
|
||||||
}
|
.app_main {
|
||||||
|
padding: 0 0.5em;
|
||||||
footer {
|
}
|
||||||
flex: 0 1 0.2em;
|
|
||||||
}
|
.warning {
|
||||||
}
|
background-color: firebrick;
|
||||||
|
text-align: center;
|
||||||
.warning {
|
padding: 0.5em 0.4em;
|
||||||
background-color: firebrick;
|
max-width: 1100px;
|
||||||
text-align: center;
|
margin: 0 auto;
|
||||||
padding: 0.5em 0.4em;
|
|
||||||
max-width: 1100px;
|
border-radius: 0 0 1em 1em;
|
||||||
margin: 0 auto;
|
}
|
||||||
|
|
||||||
border-radius: 0 0 1em 1em;
|
// FOOTER
|
||||||
}
|
footer.app_footer {
|
||||||
|
max-width: 100%;
|
||||||
// FOOTER
|
padding: 0.5em;
|
||||||
footer.app_footer {
|
|
||||||
max-width: 100%;
|
img {
|
||||||
padding: 0.5em;
|
width: 1.1em;
|
||||||
|
vertical-align: text-bottom;
|
||||||
z-index: 10;
|
}
|
||||||
|
|
||||||
background: #111;
|
z-index: 10;
|
||||||
color: white;
|
|
||||||
|
background: #111;
|
||||||
text-align: center;
|
color: white;
|
||||||
vertical-align: middle;
|
|
||||||
}
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,174 +1,159 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="app_container">
|
<div class="app_container">
|
||||||
<transition name="modal-anim">
|
<transition name="modal-anim">
|
||||||
<keep-alive>
|
<keep-alive>
|
||||||
<TrainModal v-if="store.chosenModalTrainId" />
|
<TrainModal v-if="store.chosenModalTrainId" />
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
</transition>
|
</transition>
|
||||||
|
|
||||||
<UpdatePrompt />
|
<AppHeader :current-lang="currentLang" @change-lang="changeLang" />
|
||||||
|
|
||||||
<AppHeader :current-lang="currentLang" @change-lang="changeLang" />
|
<main class="app_main">
|
||||||
|
<router-view v-slot="{ Component }">
|
||||||
<main class="app_main">
|
<keep-alive exclude="JournalView,SceneryView">
|
||||||
<router-view v-slot="{ Component }">
|
<component :is="Component" :key="$route.name" />
|
||||||
<keep-alive exclude="JournalView">
|
</keep-alive>
|
||||||
<component :is="Component" :key="$route.name" />
|
</router-view>
|
||||||
</keep-alive>
|
</main>
|
||||||
</router-view>
|
|
||||||
</main>
|
<footer class="app_footer">
|
||||||
|
©
|
||||||
<footer class="app_footer">
|
<a href="https://td2.info.pl/profile/?u=20777" target="_blank">Spythere</a>
|
||||||
©
|
{{ new Date().getUTCFullYear() }} |
|
||||||
<a href="https://td2.info.pl/profile/?u=20777" target="_blank">Spythere</a>
|
<a :href="releaseURL" target="_blank">v{{ VERSION }}{{ isOnProductionHost ? '' : 'dev' }}</a>
|
||||||
{{ new Date().getUTCFullYear() }} | <a :href="releaseURL" target="_blank">v{{ VERSION }}</a>
|
<br />
|
||||||
|
<a href="https://discord.gg/x2mpNN3svk">
|
||||||
<div style="display: none">∫ ukryta taktyczna całka do programowania w HTMLu</div>
|
<img src="/images/icon-discord.png" alt="" /> <b>{{ $t('footer.discord') }}</b>
|
||||||
</footer>
|
</a>
|
||||||
</div>
|
|
||||||
</template>
|
<div style="display: none">∫ ukryta taktyczna całka do programowania w HTMLu</div>
|
||||||
|
</footer>
|
||||||
<script lang="ts">
|
</div>
|
||||||
import { computed, defineComponent, KeepAlive, provide, ref, watch } from 'vue';
|
</template>
|
||||||
|
|
||||||
import Clock from './components/App/Clock.vue';
|
<script lang="ts">
|
||||||
|
import { defineComponent, watch } from 'vue';
|
||||||
import packageInfo from '.././package.json';
|
|
||||||
|
import Clock from './components/App/Clock.vue';
|
||||||
import StatusIndicator from './components/App/StatusIndicator.vue';
|
|
||||||
import SelectBox from './components/Global/SelectBox.vue';
|
import packageInfo from '.././package.json';
|
||||||
import { useStore } from './store/store';
|
import { regions } from './data/options.json';
|
||||||
import TrainModal from './components/Global/TrainModal.vue';
|
|
||||||
import StorageManager from './scripts/managers/storageManager';
|
import { useStore } from './store/mainStore';
|
||||||
import imageMixin from './mixins/imageMixin';
|
import StatusIndicator from './components/App/StatusIndicator.vue';
|
||||||
import AppHeader from './components/App/AppHeader.vue';
|
import TrainModal from './components/Global/TrainModal.vue';
|
||||||
import axios from 'axios';
|
import AppHeader from './components/App/AppHeader.vue';
|
||||||
import UpdatePrompt from './components/App/UpdatePrompt.vue';
|
import axios from 'axios';
|
||||||
import { VERSION } from 'vue-i18n';
|
import StorageManager from './managers/storageManager';
|
||||||
import { RouterView } from 'vue-router';
|
|
||||||
import useCustomSW from './mixins/useCustomSW';
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
export default defineComponent({
|
Clock,
|
||||||
components: {
|
StatusIndicator,
|
||||||
Clock,
|
TrainModal,
|
||||||
StatusIndicator,
|
AppHeader
|
||||||
SelectBox,
|
},
|
||||||
TrainModal,
|
|
||||||
AppHeader,
|
data: () => ({
|
||||||
UpdatePrompt,
|
VERSION: packageInfo.version,
|
||||||
},
|
store: useStore(),
|
||||||
|
|
||||||
mixins: [imageMixin],
|
currentLang: 'pl',
|
||||||
|
releaseURL: '',
|
||||||
setup() {
|
isOnProductionHost: location.hostname == 'stacjownik-td2.web.app'
|
||||||
const store = useStore();
|
}),
|
||||||
store.connectToAPI();
|
|
||||||
|
created() {
|
||||||
const { offlineReady } = useCustomSW();
|
this.loadLang();
|
||||||
|
this.store.connectToAPI();
|
||||||
const isFilterCardVisible = ref(false);
|
|
||||||
|
this.store.isOffline = !window.navigator.onLine;
|
||||||
provide('isFilterCardVisible', isFilterCardVisible);
|
|
||||||
|
window.addEventListener('offline', () => {
|
||||||
return {
|
this.store.isOffline = true;
|
||||||
store,
|
|
||||||
isFilterCardVisible,
|
this.store.activeData.activeSceneries = [];
|
||||||
onlineDispatchers: computed(() =>
|
this.store.activeData.trains = [];
|
||||||
store.stationList.filter((station) => station.onlineInfo && station.onlineInfo.region == store.region.id)
|
this.store.activeData.connectedSocketCount = 0;
|
||||||
),
|
|
||||||
|
this.store.setStatuses();
|
||||||
dispatcherDataStatus: store.dataStatuses.dispatchers,
|
});
|
||||||
};
|
|
||||||
},
|
window.addEventListener('online', () => {
|
||||||
|
this.store.isOffline = false;
|
||||||
data: () => ({
|
});
|
||||||
VERSION: packageInfo.version,
|
},
|
||||||
|
|
||||||
currentLang: 'pl',
|
async mounted() {
|
||||||
releaseURL: '',
|
this.setReleaseURL();
|
||||||
}),
|
|
||||||
|
watch(
|
||||||
created() {
|
() => this.store.blockScroll,
|
||||||
this.loadLang();
|
(value) => {
|
||||||
|
if (value) document.body.classList.add('no-scroll');
|
||||||
this.store.isOffline = !window.navigator.onLine;
|
else document.body.classList.remove('no-scroll');
|
||||||
|
}
|
||||||
window.addEventListener('offline', () => {
|
);
|
||||||
this.store.isOffline = true;
|
},
|
||||||
|
|
||||||
this.store.apiData = {
|
watch: {
|
||||||
stations: [],
|
'$route.query.region': {
|
||||||
dispatchers: [],
|
immediate: true,
|
||||||
trains: [],
|
handler(regionQuery: string) {
|
||||||
connectedSocketCount: 0,
|
if (regionQuery) {
|
||||||
};
|
this.store.region.id =
|
||||||
|
regions.find(
|
||||||
this.store.setOnlineData();
|
(reg) =>
|
||||||
});
|
reg.id == regionQuery.toLocaleLowerCase() ||
|
||||||
|
reg.value.toLocaleLowerCase() == regionQuery.toLocaleLowerCase()
|
||||||
window.addEventListener('online', () => {
|
)?.id || 'eu';
|
||||||
this.store.isOffline = false;
|
}
|
||||||
});
|
}
|
||||||
},
|
}
|
||||||
|
},
|
||||||
async mounted() {
|
|
||||||
this.setReleaseURL();
|
methods: {
|
||||||
|
changeLang(lang: string) {
|
||||||
watch(
|
this.$i18n.locale = lang;
|
||||||
() => this.store.blockScroll,
|
this.currentLang = lang;
|
||||||
(value) => {
|
|
||||||
if (value) {
|
StorageManager.setStringValue('lang', lang);
|
||||||
document.body.classList.add('no-scroll');
|
},
|
||||||
return;
|
|
||||||
}
|
async setReleaseURL() {
|
||||||
|
try {
|
||||||
document.body.classList.remove('no-scroll');
|
const releaseData = await (
|
||||||
}
|
await axios.get('https://api.github.com/repos/Spythere/stacjownik/releases/latest')
|
||||||
);
|
).data;
|
||||||
},
|
|
||||||
|
if (!releaseData) return;
|
||||||
methods: {
|
|
||||||
changeLang(lang: string) {
|
this.releaseURL = releaseData.html_url;
|
||||||
this.$i18n.locale = lang;
|
} catch (error) {
|
||||||
this.currentLang = lang;
|
console.error(`Wystąpił błąd podczas pobierania danych z API GitHuba: ${error}`);
|
||||||
|
return;
|
||||||
StorageManager.setStringValue('lang', lang);
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async setReleaseURL() {
|
loadLang() {
|
||||||
try {
|
const storageLang = StorageManager.getStringValue('lang');
|
||||||
const releaseData = await (
|
|
||||||
await axios.get('https://api.github.com/repos/Spythere/stacjownik/releases/latest')
|
if (storageLang) {
|
||||||
).data;
|
this.changeLang(storageLang);
|
||||||
|
return;
|
||||||
if (!releaseData) return;
|
}
|
||||||
|
|
||||||
this.releaseURL = releaseData.html_url;
|
if (!window.navigator.language) return;
|
||||||
} catch (error) {
|
|
||||||
console.error(`Wystąpił błąd podczas pobierania danych z API GitHuba: ${error}`);
|
const naviLanguage = window.navigator.language.toString();
|
||||||
return;
|
|
||||||
}
|
if (naviLanguage.includes('en')) {
|
||||||
},
|
this.changeLang('en');
|
||||||
|
return;
|
||||||
loadLang() {
|
}
|
||||||
const storageLang = StorageManager.getStringValue('lang');
|
}
|
||||||
|
}
|
||||||
if (storageLang) {
|
});
|
||||||
this.changeLang(storageLang);
|
</script>
|
||||||
return;
|
|
||||||
}
|
<style lang="scss" src="./App.scss"></style>
|
||||||
|
|
||||||
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 |
@@ -1,275 +1,214 @@
|
|||||||
<template>
|
<template>
|
||||||
<header class="app_header">
|
<header class="app_header">
|
||||||
<div class="header_container">
|
<div class="header_container">
|
||||||
<div class="header_icons">
|
<div class="header_icons">
|
||||||
<span class="icons-top">
|
<span class="icons-top">
|
||||||
<img :src="getIcon('pl')" alt="icon-pl" @click="changeLang('en')" v-if="currentLang == 'pl'" />
|
<img
|
||||||
<img :src="getIcon('en', 'jpg')" alt="icon-en" @click="changeLang('pl')" v-else />
|
src="/images/icon-pl.svg"
|
||||||
</span>
|
alt="icon-pl"
|
||||||
|
@click="changeLang('en')"
|
||||||
<span class="icons-bottom">
|
v-if="currentLang == 'pl'"
|
||||||
<a href="https://www.paypal.com/paypalme/spythere" target="_blank">
|
/>
|
||||||
<img :src="getIcon('dollar')" alt="icon paypal" />
|
<img src="/images/icon-en.jpg" alt="icon-en" @click="changeLang('pl')" v-else />
|
||||||
</a>
|
</span>
|
||||||
|
</div>
|
||||||
<a href="https://discord.gg/x2mpNN3svk" target="_blank">
|
|
||||||
<img :src="getIcon('discord', 'png')" alt="icon discord" />
|
<div class="header_body">
|
||||||
</a>
|
<StatusIndicator />
|
||||||
</span>
|
|
||||||
</div>
|
<span class="header_brand">
|
||||||
|
<router-link to="/">
|
||||||
<div class="header_body">
|
<img src="/images/stacjownik-header-logo.svg" alt="Stacjownik" />
|
||||||
<StatusIndicator />
|
</router-link>
|
||||||
|
</span>
|
||||||
<span class="header_brand">
|
|
||||||
<router-link to="/">
|
<span class="header_info">
|
||||||
<img :src="getImage('stacjownik-header-logo.svg')" alt="Stacjownik" />
|
<Clock />
|
||||||
</router-link>
|
|
||||||
</span>
|
<div class="info_counter">
|
||||||
|
<img src="/images/icon-dispatcher.svg" alt="icon dispatcher" />
|
||||||
<span class="header_info">
|
<span class="text--primary">{{ onlineDispatchersCount }}</span>
|
||||||
<Clock />
|
|
||||||
|
<!-- <span class="g-tooltip">
|
||||||
<div class="info_counter">
|
<b class="text--primary">{{ factorU }}U</b>
|
||||||
<img :src="getIcon('dispatcher')" alt="icon dispatcher" />
|
<div class="content">Test</div>
|
||||||
<span class="text--primary">{{ onlineDispatchersCount }}</span>
|
</span> -->
|
||||||
<span class="text--grayed"> / </span>
|
|
||||||
<span class="text--primary">{{ onlineTrainsCount }}</span>
|
<span class="text--grayed"> / </span>
|
||||||
<img :src="getIcon('train')" alt="icon train" />
|
<span class="text--primary">{{ onlineTrainsCount }}</span>
|
||||||
</div>
|
<img src="/images/icon-train.svg" alt="icon train" />
|
||||||
|
</div>
|
||||||
<span class="info_region">
|
|
||||||
<SelectBox :itemList="computedRegions" :defaultItemIndex="0" @selected="changeRegion" />
|
<div class="info_region">
|
||||||
</span>
|
<RegionDropdown />
|
||||||
</span>
|
</div>
|
||||||
|
</span>
|
||||||
<span class="header_links">
|
|
||||||
<router-link class="route" active-class="route-active" to="/" exact>
|
<span class="header_links">
|
||||||
{{ $t('app.sceneries') }}
|
<router-link class="route" active-class="route-active" to="/" exact>
|
||||||
</router-link>
|
{{ $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" to="/trains">{{
|
||||||
<router-link
|
$t('app.trains')
|
||||||
class="route"
|
}}</router-link>
|
||||||
active-class="route-active"
|
/
|
||||||
:data-active="$route.path.startsWith('/journal')"
|
<router-link
|
||||||
to="/journal"
|
class="route"
|
||||||
>
|
active-class="route-active"
|
||||||
{{ $t('app.journal') }}
|
:data-active="$route.path.startsWith('/journal')"
|
||||||
</router-link>
|
to="/journal"
|
||||||
</span>
|
>
|
||||||
</div>
|
{{ $t('app.journal') }}
|
||||||
</div>
|
</router-link>
|
||||||
</header>
|
</span>
|
||||||
</template>
|
</div>
|
||||||
<script lang="ts">
|
</div>
|
||||||
import { defineComponent } from 'vue';
|
</header>
|
||||||
import { useStore } from '../../store/store';
|
</template>
|
||||||
import options from '../../data/options.json';
|
<script lang="ts">
|
||||||
import imageMixin from '../../mixins/imageMixin';
|
import { defineComponent } from 'vue';
|
||||||
import SelectBox from '../Global/SelectBox.vue';
|
import { useStore } from '../../store/mainStore';
|
||||||
import StatusIndicator from './StatusIndicator.vue';
|
import StatusIndicator from './StatusIndicator.vue';
|
||||||
import Clock from './Clock.vue';
|
import Clock from './Clock.vue';
|
||||||
|
import RegionDropdown from '../Global/RegionDropdown.vue';
|
||||||
export default defineComponent({
|
|
||||||
emits: ['changeLang'],
|
export default defineComponent({
|
||||||
mixins: [imageMixin],
|
emits: ['changeLang'],
|
||||||
props: {
|
props: {
|
||||||
currentLang: {
|
currentLang: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
setup() {
|
|
||||||
return {
|
setup() {
|
||||||
store: useStore(),
|
return {
|
||||||
};
|
store: useStore()
|
||||||
},
|
};
|
||||||
methods: {
|
},
|
||||||
changeRegion(region: { id: string; value: string }) {
|
|
||||||
this.store.changeRegion(region);
|
methods: {
|
||||||
},
|
changeLang(lang: string) {
|
||||||
changeLang(lang: string) {
|
this.$emit('changeLang', lang);
|
||||||
this.$emit('changeLang', lang);
|
}
|
||||||
},
|
},
|
||||||
},
|
|
||||||
computed: {
|
computed: {
|
||||||
onlineTrainsCount() {
|
onlineTrainsCount() {
|
||||||
return this.store.trainList.filter((train) => train.online).length;
|
return this.store.trainList.filter((train) => train.region == this.store.region.id).length;
|
||||||
},
|
},
|
||||||
onlineDispatchersCount() {
|
|
||||||
return this.store.stationList.filter(
|
onlineDispatchersCount() {
|
||||||
(station) => station.onlineInfo && station.onlineInfo.region == this.store.region.id
|
return this.store.onlineSceneryList.filter(
|
||||||
).length;
|
(scenery) => scenery.region == this.store.region.id
|
||||||
},
|
).length;
|
||||||
computedRegions() {
|
},
|
||||||
return options.regions.map((region) => {
|
|
||||||
const regionStationCount =
|
factorU() {
|
||||||
this.store.apiData.stations?.filter((station) => station.region == region.id && station.isOnline).length || 0;
|
return this.onlineDispatchersCount == 0
|
||||||
const regionTrainCount =
|
? '-'
|
||||||
this.store.apiData.trains?.filter((train) => train.region == region.id && train.online).length || 0;
|
: (this.onlineTrainsCount / this.onlineDispatchersCount).toFixed(2);
|
||||||
return {
|
}
|
||||||
id: region.id,
|
},
|
||||||
value: `${region.value} <div class='text--grayed'>${regionStationCount} / ${regionTrainCount}</div>`,
|
components: { StatusIndicator, Clock, RegionDropdown }
|
||||||
selectedValue: region.value,
|
});
|
||||||
};
|
</script>
|
||||||
});
|
<style lang="scss" scoped>
|
||||||
},
|
@import '../../styles/variables.scss';
|
||||||
},
|
@import '../../styles/responsive.scss';
|
||||||
components: { SelectBox, StatusIndicator, Clock },
|
|
||||||
});
|
// HEADER
|
||||||
</script>
|
.app_header {
|
||||||
<style lang="scss" scoped>
|
display: flex;
|
||||||
@import '../../styles/variables.scss';
|
justify-content: center;
|
||||||
@import '../../styles/responsive.scss';
|
|
||||||
|
position: relative;
|
||||||
// HEADER
|
background-color: $primaryCol;
|
||||||
.app_header {
|
}
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
.header {
|
||||||
|
&_body {
|
||||||
position: relative;
|
position: relative;
|
||||||
background-color: $primaryCol;
|
max-width: 20em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header {
|
&_container {
|
||||||
&_body {
|
display: flex;
|
||||||
max-width: 21em;
|
justify-content: center;
|
||||||
position: relative;
|
|
||||||
|
border-radius: 0 0 1em 1em;
|
||||||
@include smallScreen {
|
|
||||||
max-width: 18em;
|
@include smallScreen {
|
||||||
}
|
position: relative;
|
||||||
}
|
margin-top: 0.5em;
|
||||||
|
}
|
||||||
&_container {
|
}
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
&_brand {
|
||||||
position: relative;
|
display: flex;
|
||||||
|
|
||||||
width: 1350px;
|
img {
|
||||||
padding: 0.5em 0.3em 0 0.3em;
|
width: 100%;
|
||||||
border-radius: 0 0 1em 1em;
|
|
||||||
}
|
margin: 0 auto;
|
||||||
|
}
|
||||||
&_brand {
|
}
|
||||||
display: flex;
|
|
||||||
|
&_info {
|
||||||
img {
|
display: grid;
|
||||||
width: 100%;
|
grid-template-columns: 1fr 1fr 1fr;
|
||||||
margin: 0 auto;
|
font-size: 1.15em;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
&_links {
|
||||||
&_info {
|
display: flex;
|
||||||
display: grid;
|
justify-content: center;
|
||||||
grid-template-columns: 1fr 1fr 1fr;
|
|
||||||
max-width: 100%;
|
border-radius: 0.7em;
|
||||||
|
|
||||||
font-size: 1.2em;
|
font-size: 1.25em;
|
||||||
}
|
padding: 0.5em;
|
||||||
|
}
|
||||||
&_links {
|
|
||||||
display: flex;
|
&_icons {
|
||||||
justify-content: center;
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
border-radius: 0.7em;
|
top: 0;
|
||||||
|
|
||||||
font-size: 1.25em;
|
padding: 0.5em;
|
||||||
padding: 0.5em;
|
|
||||||
}
|
@include smallScreen {
|
||||||
|
transform: translateX(85%);
|
||||||
&_icons {
|
}
|
||||||
position: absolute;
|
}
|
||||||
right: 0;
|
}
|
||||||
top: 0;
|
|
||||||
height: 100%;
|
// ICONS
|
||||||
|
.icons-top {
|
||||||
display: flex;
|
img {
|
||||||
flex-direction: column;
|
width: 2.5em;
|
||||||
justify-content: flex-end;
|
cursor: pointer;
|
||||||
align-items: flex-end;
|
}
|
||||||
padding: 0.5em 0.5em;
|
}
|
||||||
|
|
||||||
@include smallScreen() {
|
// COUNTER
|
||||||
right: auto;
|
.info_counter {
|
||||||
left: 0.75em;
|
display: flex;
|
||||||
padding: 0;
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
align-items: center;
|
|
||||||
}
|
span {
|
||||||
}
|
margin: 0 0.15em;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ICONS
|
img {
|
||||||
.icons {
|
width: 1.35em;
|
||||||
position: relative;
|
}
|
||||||
|
}
|
||||||
&-top {
|
|
||||||
img {
|
.info_region {
|
||||||
width: 2.5em;
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
cursor: pointer;
|
}
|
||||||
}
|
</style>
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</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>
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -162,9 +194,9 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { DataStatus } from '../../scripts/enums/DataStatus';
|
import { StoreState } from '../../store/typings';
|
||||||
import { useStore } from '../../store/store';
|
import { useStore } from '../../store/mainStore';
|
||||||
import { StoreState } from '../../store/storeTypes';
|
import { Status } from '../../typings/common';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
data() {
|
data() {
|
||||||
@@ -172,20 +204,20 @@ export default defineComponent({
|
|||||||
tooltipActive: false,
|
tooltipActive: false,
|
||||||
indicator: {
|
indicator: {
|
||||||
offline: false,
|
offline: false,
|
||||||
status: DataStatus.Loading,
|
status: Status.Data.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
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.setSignalStatus(DataStatus.Loading);
|
this.setSignalStatus(Status.Data.Loading);
|
||||||
},
|
},
|
||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
@@ -193,7 +225,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
dataStatus: store.dataStatuses,
|
dataStatus: store.dataStatuses,
|
||||||
store,
|
store
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -208,80 +240,80 @@ export default defineComponent({
|
|||||||
const dispatcherDataStatus = statuses.dispatchers;
|
const dispatcherDataStatus = statuses.dispatchers;
|
||||||
|
|
||||||
if (this.store.isOffline) {
|
if (this.store.isOffline) {
|
||||||
this.setSignalStatus(DataStatus.Initialized);
|
this.setSignalStatus(Status.Data.Initialized);
|
||||||
this.indicator.status = DataStatus.Initialized;
|
this.indicator.status = Status.Data.Initialized;
|
||||||
this.indicator.message = 'data-status.S1-offline';
|
this.indicator.message = 'data-status.S1-offline';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connectionStatus == DataStatus.Error) {
|
if (connectionStatus == Status.Data.Error) {
|
||||||
this.setSignalStatus(connectionStatus);
|
this.setSignalStatus(connectionStatus);
|
||||||
this.indicator.status = connectionStatus;
|
this.indicator.status = connectionStatus;
|
||||||
this.indicator.message = 'data-status.S1a-connection';
|
this.indicator.message = 'data-status.S1a-connection';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sceneryDataStatus == DataStatus.Error) {
|
if (sceneryDataStatus == Status.Data.Error) {
|
||||||
this.setSignalStatus(sceneryDataStatus);
|
this.setSignalStatus(sceneryDataStatus);
|
||||||
this.indicator.status = sceneryDataStatus;
|
this.indicator.status = sceneryDataStatus;
|
||||||
this.indicator.message = 'data-status.S1a-sceneries';
|
this.indicator.message = 'data-status.S1a-sceneries';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trainsDataStatus == DataStatus.Warning) {
|
if (trainsDataStatus == Status.Data.Warning) {
|
||||||
this.setSignalStatus(trainsDataStatus);
|
this.setSignalStatus(trainsDataStatus);
|
||||||
this.indicator.status = trainsDataStatus;
|
this.indicator.status = trainsDataStatus;
|
||||||
this.indicator.message = 'data-status.S5-trains';
|
this.indicator.message = 'data-status.S5-trains';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dispatcherDataStatus == DataStatus.Warning) {
|
if (dispatcherDataStatus == Status.Data.Warning) {
|
||||||
this.setSignalStatus(dispatcherDataStatus);
|
this.setSignalStatus(dispatcherDataStatus);
|
||||||
this.indicator.status = dispatcherDataStatus;
|
this.indicator.status = dispatcherDataStatus;
|
||||||
this.indicator.message = 'data-status.S5-dispatchers';
|
this.indicator.message = 'data-status.S5-dispatchers';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sceneryDataStatus == DataStatus.Loaded) {
|
if (sceneryDataStatus == Status.Data.Loaded) {
|
||||||
this.setSignalStatus(DataStatus.Loaded);
|
this.setSignalStatus(Status.Data.Loaded);
|
||||||
|
|
||||||
this.indicator.status = DataStatus.Loaded;
|
this.indicator.status = Status.Data.Loaded;
|
||||||
this.indicator.message = 'data-status.S2';
|
this.indicator.message = 'data-status.S2';
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
setSignalStatus(status: DataStatus) {
|
setSignalStatus(status: Status.Data) {
|
||||||
this.greenLight = false;
|
this.greenLight = false;
|
||||||
this.greenBlinkLight = false;
|
this.greenBlinkLight = false;
|
||||||
this.redTopLight = false;
|
this.redTopLight = false;
|
||||||
this.orangeLight = false;
|
this.orangeLight = false;
|
||||||
this.redBottomLight = false;
|
this.redBottomLight = false;
|
||||||
|
|
||||||
if (status == DataStatus.Initialized) {
|
if (status == Status.Data.Initialized) {
|
||||||
this.redTopLight = true;
|
this.redTopLight = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status == DataStatus.Loaded) {
|
if (status == Status.Data.Loaded) {
|
||||||
this.greenLight = true;
|
this.greenLight = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status == DataStatus.Warning) {
|
if (status == Status.Data.Warning) {
|
||||||
this.orangeLight = true;
|
this.orangeLight = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status == DataStatus.Error) {
|
if (status == Status.Data.Error) {
|
||||||
this.redTopLight = true;
|
this.redTopLight = true;
|
||||||
this.redBottomLight = true;
|
this.redBottomLight = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status == DataStatus.Loading) {
|
if (status == Status.Data.Loading) {
|
||||||
this.greenBlinkLight = true;
|
this.greenBlinkLight = true;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -303,9 +335,11 @@ export default defineComponent({
|
|||||||
|
|
||||||
.status-indicator {
|
.status-indicator {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 110%;
|
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
|
|
||||||
|
transform: translateX(1.5em);
|
||||||
}
|
}
|
||||||
|
|
||||||
.indicator {
|
.indicator {
|
||||||
@@ -330,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;
|
||||||
|
|
||||||
@@ -354,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,168 +0,0 @@
|
|||||||
<template>
|
|
||||||
<transition name="modal-anim">
|
|
||||||
<section class="update-modal card" v-if="releaseData && modalOpen">
|
|
||||||
<h2 class="modal_header text--primary">
|
|
||||||
<img :src="getImage('stacjownik-header-logo.svg')" alt="stacjownik logo" />
|
|
||||||
|
|
||||||
{{ releaseData.tag_name }}
|
|
||||||
</h2>
|
|
||||||
|
|
||||||
<div class="horizontal"></div>
|
|
||||||
|
|
||||||
<div class="modal_content">
|
|
||||||
<h3>{{ $t('update.title') }}</h3>
|
|
||||||
<a :href="releaseData.html_url" target="_blank">{{ $t('update.release-link') }}</a>
|
|
||||||
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
|
|
||||||
<p>{{ $t('update.paragraph1') }}</p>
|
|
||||||
|
|
||||||
<!-- <div class="modal_changelog" v-html="markdownReleaseBody"></div> -->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal_actions">
|
|
||||||
<button class="btn btn--option" @click="modalOpen = false">{{ $t('update.confirm-button') }}</button>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</transition>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import axios from 'axios';
|
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
import packageInfo from '../../../package.json';
|
|
||||||
import imageMixin from '../../mixins/imageMixin';
|
|
||||||
import { ReleaseAPIData } from '../../scripts/interfaces/github_api/ReleaseAPIData';
|
|
||||||
import StorageManager from '../../scripts/managers/storageManager';
|
|
||||||
import { useStore } from '../../store/store';
|
|
||||||
|
|
||||||
|
|
||||||
const GH_LASTEST_RELEASE_URL = 'https://api.github.com/repos/Spythere/stacjownik/releases/latest';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
mixins: [imageMixin],
|
|
||||||
|
|
||||||
mounted() {
|
|
||||||
this.fetchReleases();
|
|
||||||
},
|
|
||||||
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
modalOpen: false,
|
|
||||||
|
|
||||||
releaseData: null as ReleaseAPIData | null,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
setup() {
|
|
||||||
return {
|
|
||||||
store: useStore()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
async fetchReleases() {
|
|
||||||
const storedVersion = StorageManager.getStringValue('appVersion');
|
|
||||||
const appVersion = packageInfo.version;
|
|
||||||
|
|
||||||
// Zmiana
|
|
||||||
if (appVersion != storedVersion) {
|
|
||||||
StorageManager.setStringValue('appVersion', appVersion);
|
|
||||||
|
|
||||||
// Znajdź changelog na GitHubie, jeśli jest pokaż modal
|
|
||||||
try {
|
|
||||||
const releaseData: ReleaseAPIData = await (await axios.get(GH_LASTEST_RELEASE_URL)).data;
|
|
||||||
if (!releaseData) return;
|
|
||||||
|
|
||||||
const lastReleaseVersion = releaseData.tag_name.slice(1);
|
|
||||||
|
|
||||||
if (lastReleaseVersion == appVersion) {
|
|
||||||
this.releaseData = releaseData;
|
|
||||||
this.modalOpen = true;
|
|
||||||
|
|
||||||
StorageManager.setStringValue('releaseURL', releaseData.html_url);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`Wystąpił błąd podczas pobierania danych z API GitHuba: ${error}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
@import '../../styles/card.scss';
|
|
||||||
@import '../../styles/responsive.scss';
|
|
||||||
|
|
||||||
|
|
||||||
.modal-anim {
|
|
||||||
&-enter-active,
|
|
||||||
&-leave-active {
|
|
||||||
transition: all $animDuration $animType;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-enter-from,
|
|
||||||
&-leave-to {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translate(-50%, -50%) scale(0.45);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.update-modal {
|
|
||||||
text-align: center;
|
|
||||||
background-color: var(--clr-secondary);
|
|
||||||
|
|
||||||
padding: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.horizontal {
|
|
||||||
margin: 1em 0;
|
|
||||||
|
|
||||||
height: 2px;
|
|
||||||
width: 100%;
|
|
||||||
background-color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal_header {
|
|
||||||
font-size: 1.6em;
|
|
||||||
|
|
||||||
img {
|
|
||||||
width: 50%;
|
|
||||||
vertical-align: text-top;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal_content {
|
|
||||||
font-size: 1.1em;
|
|
||||||
|
|
||||||
a {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal_actions {
|
|
||||||
margin-top: 2em;
|
|
||||||
|
|
||||||
button {
|
|
||||||
color: white;
|
|
||||||
padding: 0.5em;
|
|
||||||
font-size: 1.2em;
|
|
||||||
|
|
||||||
background-color: black;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal_changelog {
|
|
||||||
font-size: 0.8em;
|
|
||||||
margin-top: 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include smallScreen {
|
|
||||||
.update-modal {
|
|
||||||
height: auto;
|
|
||||||
max-width: 95%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="update-prompt">
|
|
||||||
<transition name="prompt-anim">
|
|
||||||
<div class="prompt_content" v-if="!hidePrompt && needRefresh">
|
|
||||||
<div>{{ $t('update.title') }}</div>
|
|
||||||
|
|
||||||
<div class="prompt_actions">
|
|
||||||
<button class="btn btn--filled" @click="updateServiceWorker(true)">{{ $t('update.confirm-button') }}</button>
|
|
||||||
<button class="btn btn--filled" @click="hidePrompt = true">{{ $t('update.later-button') }}</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</transition>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref } from 'vue';
|
|
||||||
import useCustomSW from '../../mixins/useCustomSW';
|
|
||||||
|
|
||||||
const hidePrompt = ref(false);
|
|
||||||
const { needRefresh, updateServiceWorker } = useCustomSW();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
@import '../../styles/variables.scss';
|
|
||||||
|
|
||||||
.update-prompt {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
z-index: 200;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prompt_content {
|
|
||||||
margin: 1em;
|
|
||||||
padding: 1em;
|
|
||||||
|
|
||||||
font-weight: bold;
|
|
||||||
background-color: black;
|
|
||||||
|
|
||||||
box-shadow: 0 0 10px 1px $accentCol;
|
|
||||||
border-radius: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prompt_actions {
|
|
||||||
display: flex;
|
|
||||||
margin-top: 1em;
|
|
||||||
gap: 0.5em;
|
|
||||||
|
|
||||||
button {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Animation
|
|
||||||
.prompt-anim {
|
|
||||||
&-enter-active,
|
|
||||||
&-leave-active {
|
|
||||||
transition: all 120ms ease-in;
|
|
||||||
transform: translateY(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
&-enter-from,
|
|
||||||
&-leave-to {
|
|
||||||
transform: translateY(100%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
@@ -1,24 +1,24 @@
|
|||||||
<template>
|
<template>
|
||||||
<button class="action-btn btn--filled">
|
<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';
|
||||||
|
|
||||||
.button_content {
|
.button_content {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
</style>
|
</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>
|
||||||
|
|
||||||
|
|||||||
@@ -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,225 @@
|
|||||||
|
<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 { regions as regionsJSON } from '../../data/options.json';
|
||||||
|
import { useStore } from '../../store/mainStore';
|
||||||
|
|
||||||
|
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.onlineSceneryList.filter(
|
||||||
|
(scenery) => scenery.region == region.id
|
||||||
|
).length;
|
||||||
|
|
||||||
|
const regionTrainCount =
|
||||||
|
this.store.trainList.filter((train) => train.region == region.id).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="getIcon('exit')"
|
|
||||||
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';
|
||||||
import imageMixin from "../../mixins/imageMixin";
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
mixins: [imageMixin],
|
emits: ['update:searchedValue', 'clearValue'],
|
||||||
|
|
||||||
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: any) => {
|
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>
|
||||||
|
|||||||