Compare commits

...

12 Commits

Author SHA1 Message Date
Spythere 5b629833df Merge pull request #16 - Wersja 1.7.1
Wersja 1.7.1
2023-10-31 23:05:43 +01:00
Spythere b53201a7ff hotfix 2023-10-31 23:02:58 +01:00
Spythere f0ddd0e27f custom checkboxes 2023-10-31 03:17:24 +01:00
Spythere 94bfba2c49 resolve fonts edit 2023-10-31 03:17:11 +01:00
Spythere 1e4541ef0d spawn props checking on stock upload 2023-10-28 15:40:22 +02:00
Spythere c25a55a7d9 added double manning checkbox & support 2023-10-28 15:33:09 +02:00
Spythere bea3c59405 thumbnail placeholder fix 2023-10-28 14:12:21 +02:00
Spythere 8cd43adff3 acceptable masses & speeds update 2023-10-28 13:44:55 +02:00
Spythere 5ab1963117 lock files sync 2023-10-27 16:46:57 +02:00
Spythere 50d784a0de 1.7.1 bump 2023-10-27 16:43:39 +02:00
Spythere f61135ce6b packages bump; config 2023-10-27 16:39:54 +02:00
Spythere 5e43ece1aa pwa optimize & fixes 2023-10-27 16:36:25 +02:00
37 changed files with 3989 additions and 2477 deletions
+8 -11
View File
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
@@ -8,23 +8,20 @@
<title>Pojazdownik</title>
<meta name="description" content="Edytor pociągów online do symulatora Train Driver 2" />
<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="icon" href="/favicon.ico" sizes="any" />
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
<link rel="apple-touch-icon" href="/apple-touch-icon-180x180.png" />
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5" />
<link rel="manifest" href="/site.webmanifest" />
<meta name="msapplication-TileColor" content="#da532c" />
<meta name="theme-color" content="#e4c428" />
<meta name="theme-color" content="#111" />
</head>
<body>
<noscript>
<strong>
We're sorry but Pojazdownik doesn't work properly without JavaScript enabled. Please enable it to continue.
</strong>
<strong> We're sorry but Pojazdownik doesn't work properly without JavaScript enabled. Please enable it to continue. </strong>
</noscript>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
+3741 -2306
View File
File diff suppressed because it is too large Load Diff
+3 -2
View File
@@ -1,6 +1,6 @@
{
"name": "pojazdownik",
"version": "1.7.0",
"version": "1.7.1",
"private": true,
"scripts": {
"dev": "vite",
@@ -19,6 +19,7 @@
},
"devDependencies": {
"@rushstack/eslint-patch": "^1.3.3",
"@vite-pwa/assets-generator": "^0.0.10",
"@vitejs/plugin-vue": "^4.1.0",
"@vue/eslint-config-prettier": "^8.0.0",
"@vue/eslint-config-typescript": "^12.0.0",
@@ -28,7 +29,7 @@
"sass": "^1.59.3",
"typescript": "^5.0.2",
"vite": "^4.2.1",
"vite-plugin-pwa": "^0.14.6",
"vite-plugin-pwa": "^0.16.5",
"vue-tsc": "^1.2.0"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

+24
View File
@@ -0,0 +1,24 @@
<svg width="500" height="500" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
<mask id="path-1-inside-1_102_63" fill="white">
<path d="M0 250C0 111.929 111.929 6.10352e-05 250 6.10352e-05C388.071 6.10352e-05 500 111.929 500 250C500 388.071 388.071 500 250 500C111.929 500 0 388.071 0 250Z"/>
</mask>
<path d="M0 250C0 111.929 111.929 6.10352e-05 250 6.10352e-05C388.071 6.10352e-05 500 111.929 500 250C500 388.071 388.071 500 250 500C111.929 500 0 388.071 0 250Z" fill="#242424"/>
<path d="M0 222.821C0 84.7503 111.929 -27.1785 250 -27.1785C388.071 -27.1785 500 84.7503 500 222.821V250C500 126.939 388.071 27.1787 250 27.1787C111.929 27.1787 0 126.939 0 250V222.821ZM500 277.179C500 415.25 388.071 527.179 250 527.179C111.929 527.179 0 415.25 0 277.179V250C0 373.061 111.929 472.821 250 472.821C388.071 472.821 500 373.061 500 250V277.179ZM0 500V6.10352e-05V500ZM500 6.10352e-05V500V6.10352e-05Z" fill="#FFD600" mask="url(#path-1-inside-1_102_63)"/>
<path d="M210.369 301.604C210.369 301.604 210.369 341.807 210.369 364.846C210.369 387.885 202.798 417.491 171.591 417.491C140.385 417.491 132.813 417.491 132.813 417.491L132.812 78.125L250.754 78.125C274.312 78.125 294.504 80.9665 311.331 86.6494C328.311 92.1788 342.232 99.8585 353.093 109.689C364.107 119.519 372.214 131.115 377.415 144.478C382.616 157.84 385.217 172.278 385.217 187.791C385.217 204.533 382.54 219.892 377.186 233.869C371.832 247.846 363.648 259.827 352.634 269.81C341.62 279.794 327.623 287.627 310.643 293.31C293.816 298.839 273.853 301.604 250.754 301.604L210.369 301.604ZM210.369 242.854L250.754 242.854C270.946 242.854 285.479 238.016 294.351 228.34C303.224 218.663 307.66 205.147 307.66 187.791C307.66 180.111 306.512 173.123 304.218 166.825C301.923 160.528 298.405 155.152 293.663 150.698C289.074 146.09 283.184 142.558 275.995 140.1C268.958 137.643 260.544 136.414 250.754 136.414L210.369 136.414L210.369 242.854Z" fill="url(#paint0_linear_102_63)"/>
<path d="M239.215 301.604C239.215 301.604 239.215 341.807 239.215 364.846C239.215 387.885 231.643 417.491 200.437 417.491C169.231 417.491 161.659 417.491 161.659 417.491L161.658 78.125L279.6 78.125C303.158 78.125 323.35 80.9665 340.177 86.6494C357.157 92.1788 371.077 99.8585 381.938 109.689C392.952 119.519 401.06 131.115 406.261 144.478C411.462 157.84 414.062 172.278 414.062 187.791C414.062 204.533 411.385 219.892 406.031 233.869C400.677 247.846 392.493 259.827 381.479 269.81C370.465 279.794 356.468 287.627 339.488 293.31C322.662 298.839 302.699 301.604 279.6 301.604L239.215 301.604ZM239.215 242.854L279.6 242.854C299.792 242.854 314.325 238.016 323.197 228.34C332.069 218.663 336.505 205.147 336.505 187.791C336.505 180.111 335.358 173.123 333.064 166.825C330.769 160.528 327.251 155.152 322.509 150.698C317.919 146.09 312.03 142.558 304.84 140.1C297.804 137.643 289.39 136.414 279.6 136.414L239.215 136.414L239.215 242.854Z" fill="url(#paint1_linear_102_63)"/>
<path d="M210.685 301.604C210.685 301.604 210.685 341.807 210.685 364.846C210.685 387.885 203.082 417.491 171.749 417.491C140.416 417.491 132.813 417.491 132.813 417.491L132.812 78.125L251.233 78.125C274.887 78.125 295.161 80.9665 312.057 86.6494C329.105 92.1788 343.083 99.8585 353.988 109.689C365.046 119.519 373.187 131.115 378.409 144.478C383.631 157.84 386.242 172.278 386.242 187.791C386.242 204.533 383.555 219.892 378.179 233.869C372.803 247.846 364.586 259.827 353.527 269.81C342.468 279.794 328.414 287.627 311.365 293.31C294.47 298.839 274.426 301.604 251.233 301.604L210.685 301.604ZM210.685 242.854L251.233 242.854C271.508 242.854 286.099 238.016 295.008 228.34C303.916 218.663 308.37 205.147 308.37 187.791C308.37 180.111 307.218 173.123 304.914 166.825C302.611 160.528 299.078 155.152 294.316 150.698C289.709 146.09 283.795 142.558 276.576 140.1C269.511 137.643 261.063 136.414 251.233 136.414L210.685 136.414L210.685 242.854Z" fill="url(#paint2_radial_102_63)"/>
<defs>
<linearGradient id="paint0_linear_102_63" x1="259.015" y1="78.125" x2="259.015" y2="417.491" gradientUnits="userSpaceOnUse">
<stop offset="0.135417" stop-color="#FFD600"/>
<stop offset="1"/>
</linearGradient>
<linearGradient id="paint1_linear_102_63" x1="287.86" y1="78.125" x2="287.86" y2="417.491" gradientUnits="userSpaceOnUse">
<stop offset="0.135417" stop-color="#FFD600"/>
<stop offset="1"/>
</linearGradient>
<radialGradient id="paint2_radial_102_63" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(259.527 247.808) rotate(0.36307) scale(345.948 325.206)">
<stop offset="0.484375" stop-color="white"/>
<stop offset="1"/>
</radialGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 4.5 KiB

+14 -3
View File
@@ -5,15 +5,26 @@
"description": "Generator składów online dla symulatora Train Driver 2",
"icons": [
{
"src": "/android-chrome-192x192.png",
"src": "pwa-64x64.png",
"sizes": "64x64",
"type": "image/png"
},
{
"src": "pwa-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/android-chrome-512x512.png",
"src": "pwa-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any maskable"
"purpose": "any"
},
{
"src": "maskable-icon-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
}
],
"theme_color": "#2c3149",
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

+14 -4
View File
@@ -5,19 +5,29 @@
"description": "Generator składów online dla symulatora Train Driver 2",
"icons": [
{
"src": "/android-chrome-192x192.png",
"src": "pwa-64x64.png",
"sizes": "64x64",
"type": "image/png"
},
{
"src": "pwa-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/android-chrome-512x512.png",
"src": "pwa-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any maskable"
"purpose": "any"
},
{
"src": "maskable-icon-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
}
],
"theme_color": "#2c3149",
"background_color": "#2c3149",
"display": "standalone"
}
-18
View File
@@ -36,22 +36,4 @@ export default defineComponent({
font-size: 1em;
padding: 1em 0.5em;
}
/* HEADER SECTION */
h2 {
margin: 0;
margin-bottom: 0.5em;
color: $accentColor;
font-weight: 700;
font-size: 1.2em;
}
.header-bottom {
margin: 0;
font-size: 1.5em;
color: #d1d1d1;
}
</style>
+16 -24
View File
@@ -16,37 +16,29 @@
<transition name="tab-change" mode="out-in">
<keep-alive>
<component
:is="chosenSectionComponent"
:key="chosenSectionComponent"
></component>
<component :is="chosenSectionComponent"></component>
</keep-alive>
</transition>
</section>
</template>
<script lang="ts" setup>
import { computed, onMounted, ref } from "vue";
import { useStore } from "../../store";
import StockListTab from "../tabs/StockListTab.vue";
import StockGeneratorTab from "../tabs/StockGeneratorTab.vue";
import NumberGeneratorTab from "../tabs/NumberGeneratorTab.vue";
import WikiListTab from "../tabs/WikiListTab.vue";
import { computed, onMounted, ref } from 'vue';
import { useStore } from '../../store';
import StockListTab from '../tabs/StockListTab.vue';
import StockGeneratorTab from '../tabs/StockGeneratorTab.vue';
import NumberGeneratorTab from '../tabs/NumberGeneratorTab.vue';
import WikiListTab from '../tabs/WikiListTab.vue';
const sectionButtonRefs = ref([]);
const store = useStore();
type SectionMode = typeof store.stockSectionMode;
const sectionModes: SectionMode[] = [
"stock-list",
"wiki-list",
"number-generator",
"stock-generator",
];
const sectionModes: SectionMode[] = ['stock-list', 'wiki-list', 'number-generator', 'stock-generator'];
onMounted(() => {
window.addEventListener("keydown", (e) => {
window.addEventListener('keydown', (e) => {
if (e.target instanceof HTMLInputElement) return;
if (/[1234]/.test(e.key)) {
@@ -59,16 +51,16 @@ onMounted(() => {
const chosenSectionComponent = computed(() => {
switch (store.stockSectionMode) {
case "stock-list":
case 'stock-list':
return StockListTab;
case "wiki-list":
case 'wiki-list':
return WikiListTab;
case "stock-generator":
case 'stock-generator':
return StockGeneratorTab;
case "number-generator":
case 'number-generator':
return NumberGeneratorTab;
default:
@@ -82,7 +74,7 @@ function chooseSection(sectionId: SectionMode) {
</script>
<style lang="scss">
@import "../../styles/global.scss";
@import '../../styles/global.scss';
// Tab change animation
.tab-change {
@@ -124,14 +116,14 @@ function chooseSection(sectionId: SectionMode) {
left: 50%;
transform: translateX(-50%);
content: "";
content: '';
width: 0;
height: 2px;
transition: all 100ms;
background-color: $accentColor;
}
&[data-selected="true"]::after {
&[data-selected='true']::after {
width: 100%;
}
}
@@ -2,16 +2,13 @@
<section class="train-image-section">
<div class="train-image__content" :class="{ sponsor: store.chosenVehicle?.isSponsorsOnly }">
<img
v-if="store.chosenVehicle"
tabindex="0"
:src="getThumbnailURL(store.chosenVehicle.type, 'small')"
:src="store.chosenVehicle ? getThumbnailURL(store.chosenVehicle.type, 'small') : '/images/placeholder.jpg'"
@click="onImageClick"
@keydown.enter="onImageClick"
@error="onImageError"
type="image/jpeg"
/>
<img v-else src="/images/placeholder.jpg" alt="placeholder" />
</div>
<div class="train-image__info" v-if="store.chosenVehicle">
+56 -9
View File
@@ -79,11 +79,16 @@
</span>
</div>
<div class="stock_cold-start">
<label>
<input type="checkbox" v-model="store.isColdStart" :disabled="!locoSupportsColdStart(store.stockList[0]?.constructionType || '')" />
<div class="stock_spawn-settings">
<label v-if="store.stockSupportsColdStart" :data-checked="store.isColdStart">
<input type="checkbox" v-model="store.isColdStart" />
{{ $t('stocklist.coldstart-info') }}
</label>
<label v-if="store.stockSupportsDoubleManning" :data-checked="store.isDoubleManned">
<input type="checkbox" v-model="store.isDoubleManned" />
{{ $t('stocklist.doublemanning-info') }}
</label>
</div>
<div class="stock_warnings" v-if="stockHasWarnings">
@@ -97,7 +102,7 @@
(!)
<i18n-t keypath="stocklist.warning-too-heavy">
<template #href>
<a target="_blank" href="https://docs.google.com/spreadsheets/d/1bFXUsHsAu4youmNz-46Q1HslZaaoklvfoBDS553TnNk/edit">
<a target="_blank" href="https://docs.google.com/spreadsheets/d/1KVa5vn2d8XGkXQFwbavVudwKqUQxbLOucHWs2VYqAUE">
{{ $t('stocklist.acceptable-mass-docs') }}
</a>
</template>
@@ -158,7 +163,6 @@ import { defineComponent } from 'vue';
import { useStore } from '../../store';
import { locoSupportsColdStart } from '../../utils/locoUtils';
import warningsMixin from '../../mixins/warningsMixin';
import imageMixin from '../../mixins/imageMixin';
import stockPreviewMixin from '../../mixins/stockPreviewMixin';
@@ -188,12 +192,19 @@ export default defineComponent({
computed: {
stockString() {
if (this.store.stockList.length == 0) return '';
const includeColdStart = this.store.isColdStart && this.store.stockSupportsColdStart;
const includeDoubleManned = this.store.isDoubleManned && this.store.stockSupportsDoubleManning;
return this.store.stockList
.map((stock, i) => {
let stockTypeStr = stock.isLoco || !stock.cargo ? stock.type : `${stock.type}:${stock.cargo.id}`;
let coldStart = i == 0 && this.store.isColdStart && locoSupportsColdStart(stock.constructionType || '') ? ',c' : '';
return stockTypeStr + coldStart;
if (i == 0 && (includeColdStart || includeDoubleManned))
return `${stockTypeStr},${includeColdStart ? 'c' : ''}${includeDoubleManned ? 'd' : ''}`;
return stockTypeStr;
})
.join(';');
},
@@ -212,8 +223,6 @@ export default defineComponent({
},
methods: {
locoSupportsColdStart,
copyToClipboard() {
navigator.clipboard.writeText(this.stockString);
@@ -472,6 +481,44 @@ export default defineComponent({
}
}
.stock_spawn-settings {
display: flex;
gap: 0.5em;
label > input {
position: absolute;
clip: rect(1px, 1px, 1px, 1px);
padding: 0;
border: 0;
height: 1px;
width: 1px;
overflow: hidden;
}
label {
padding: 0.25em 0.5em;
border-radius: 0.25em;
background-color: #222;
color: #aaa;
cursor: pointer;
text-transform: uppercase;
transition: color 200ms;
&::before {
content: '\2716';
}
}
label[data-checked='true'] {
color: palegreen;
&::before {
content: '\2714';
}
}
}
.real-stock-info {
img {
height: 1.3ch;
+5 -6
View File
@@ -66,7 +66,7 @@
<td v-if="currentFilterMode == 'carriages'">{{ !isLocomotive(vehicle) ? vehicle.cargoList.length : '---' }}</td>
<td v-if="currentFilterMode == 'tractions'">
{{ isLocomotive(vehicle) ? (locoSupportsColdStart(vehicle.constructionType) ? `&check;` : '&cross;') : '---' }}
{{ isLocomotive(vehicle) ? (vehicle.coldStart ? `&check;` : '&cross;') : '---' }}
</td>
</tr>
</tbody>
@@ -86,7 +86,6 @@ import { Vehicle } from '../../types';
import { isLocomotive } from '../../utils/vehicleUtils';
import stockMixin from '../../mixins/stockMixin';
import imageMixin from '../../mixins/imageMixin';
import { locoSupportsColdStart } from '../../utils/locoUtils';
type SorterID = 'type' | 'constructionType' | 'image' | 'length' | 'mass' | 'maxSpeed' | 'cargoCount' | 'group' | 'coldStart';
@@ -143,7 +142,6 @@ export default defineComponent({
},
methods: {
locoSupportsColdStart,
isLocomotive,
toggleFilter(name: typeof this.currentFilterMode) {
@@ -180,7 +178,10 @@ export default defineComponent({
);
case 'coldStart':
return (locoSupportsColdStart(row1.vehicle.constructionType) > locoSupportsColdStart(row2.vehicle.constructionType) ? 1 : -1) * direction;
return (
((isLocomotive(row1.vehicle) && row1.vehicle.coldStart ? 1 : -1) - (isLocomotive(row2.vehicle) && row2.vehicle.coldStart ? 1 : -1)) *
direction
);
default:
break;
@@ -200,8 +201,6 @@ export default defineComponent({
(this.currentFilterMode == 'all' ||
(this.currentFilterMode == 'tractions' && isLocomotive(vehicle)) ||
(this.currentFilterMode == 'carriages' && !isLocomotive(vehicle))),
// ((this.filters.tractions && isLocomotive(vehicle)) || (this.filters.carriages && !isLocomotive(vehicle))),
}))
.sort((a, b) => this.sortTableRows(a, b));
},
+10
View File
@@ -0,0 +1,10 @@
{
"EU06": [650, 2000],
"EU07": [650, 2000],
"EU07E": [650, 2000],
"EP07": [650, 650],
"EP08": [650, 650],
"EP09": [800, 800],
"ET41": [700, 4000],
"SM42": [2400, 2400]
}
+2 -1
View File
@@ -64,7 +64,8 @@
"mass-accepted": "accepted",
"length": "Length",
"vmax": "vMax",
"coldstart-info": "Cold start heading locomotive (only locos 303E & 203E type)",
"coldstart-info": "Locomotive cold start",
"doublemanning-info": "Double manning",
"list-empty": "Stock list is empty!",
"warning-not-suitable": "EP07 & EP08 type locomotives are designed for passenger traffic only!",
"warning-passenger-too-long": "Maximum length of a passenger train may not be greater than 350m!",
+4 -3
View File
@@ -29,7 +29,7 @@
"title": "PODGLĄD WYBRANEGO POJAZDU",
"loading": "ŁADOWANIE OBRAZU...",
"desc": "Wybierz pojazd lub wagon, aby zobaczyć jego podgląd powyżej",
"sponsor-only": "* TYLKO DLA SPONSORÓW DO {0}",
"sponsor-only": "* TYLKO DLA SPONSORÓW DO {0}",
"loco-e": "ELEKTROWÓZ",
"loco-s": "SPALINOWÓZ",
"loco-ezt": "EZT",
@@ -64,7 +64,8 @@
"mass-accepted": "dopuszczalna",
"length": "Długość",
"vmax": "vMax",
"coldstart-info": "Zimny start lokomotywy czołowej (tylko elektrowozy typów 303E i 203E)",
"coldstart-info": "Zimny start",
"doublemanning-info": "Podwójna obsada",
"list-empty": "Lista pojazdów jest pusta!",
"warning-not-suitable": "Lokomotywy EP07 i EP08 są przeznaczone jedynie do ruchu pasażerskiego!",
"warning-passenger-too-long": "Maksymalna długość składów pasażerskich nie może przekraczać 350m!",
@@ -141,7 +142,7 @@
"loco-s": "Spalinowóz",
"loco-e": "Elektrowóz",
"car-passenger": "Wagon pasażerski",
"car-cargo": "Wagon towarowy"
"car-cargo": "Wagon towarowy"
},
"realstock": {
"title": "ZESTAWIENIA REALNE by",
+5 -10
View File
@@ -1,13 +1,8 @@
import { createApp } from "vue";
import { createPinia } from "pinia";
import { registerSW } from "virtual:pwa-register";
import { createApp } from 'vue';
import { createPinia } from 'pinia';
import App from "./App.vue";
import i18n from "./i18n-setup";
import App from './App.vue';
import i18n from './i18n-setup';
const pinia = createPinia();
registerSW({
immediate: true,
});
createApp(App).use(pinia).use(i18n).mount("#app");
createApp(App).use(pinia).use(i18n).mount('#app');
+10 -4
View File
@@ -73,11 +73,17 @@ export default defineComponent({
let vehicle: Vehicle | null = null;
let vehicleCargo: ICargo | null = null;
if (/^(EU|EP|ET|SM|EN|2EN|SN)/.test(type)) {
const [locoType, coldStart] = type.split(',');
const isLoco = /^(EU|EP|ET|SM|EN|2EN|SN)/.test(type);
if (isLoco) {
const [locoType, spawnProps] = type.split(',');
vehicle = this.store.locoDataList.find((loco) => loco.type == locoType) || null;
if (i == 0 && coldStart == 'c') this.store.isColdStart = true;
// Spawn settings
if (i == 0 && spawnProps) {
this.store.isColdStart = spawnProps.includes('c');
this.store.isDoubleManned = spawnProps.includes('d');
}
} else {
const [carType, cargo] = type.split(':');
vehicle = this.store.carDataList.find((car) => car.type == carType) || null;
@@ -85,7 +91,7 @@ export default defineComponent({
if (cargo) vehicleCargo = vehicle?.cargoList.find((c) => c.id == cargo) || null;
}
if (!vehicle) console.log('Brak pojazdu:', type);
if (!vehicle) console.log('Brak pojazdu / rodzaj pojazdu źle wczytany:', type);
this.addVehicle(vehicle, vehicleCargo);
});
+19
View File
@@ -22,6 +22,7 @@ export const useStore = defineStore({
chosenVehicle: null,
isColdStart: false,
isDoubleManned: false,
showSupporter: false,
imageLoading: false,
@@ -61,6 +62,24 @@ export const useStore = defineStore({
isTrainPassenger: (state) => isTrainPassenger(state),
chosenRealStock: (state) => chosenRealStock(state),
acceptableMass: (state) => acceptableMass(state),
stockSupportsColdStart: (state) => {
if (state.stockList.length == 0) return false;
if (!state.stockList[0].isLoco) return false;
const headingLoco = state.stockList[0];
return state.stockData?.props.find((stock) => stock.type == headingLoco.constructionType)?.coldStart ?? false;
},
stockSupportsDoubleManning: (state) => {
if (state.stockList.length == 0) return false;
if (!state.stockList[0].isLoco) return false;
const headingLoco = state.stockList[0];
return state.stockData?.props.find((stock) => stock.type == headingLoco.constructionType)?.doubleManned ?? false;
},
},
actions: {
+6 -6
View File
@@ -9,8 +9,8 @@ $accentColor: #e4c428;
@font-face {
font-family: 'Lato';
src:
url('$fonts/Lato-Light.woff2') format('woff2'),
url('$fonts/Lato-Light.woff') format('woff');
url('/fonts/Lato-Light.woff2') format('woff2'),
url('/fonts/Lato-Light.woff') format('woff');
font-weight: 300;
font-style: normal;
font-display: swap;
@@ -19,8 +19,8 @@ $accentColor: #e4c428;
@font-face {
font-family: 'Lato';
src:
url('$fonts/Lato-Bold.woff2') format('woff2'),
url('$fonts/Lato-Bold.woff') format('woff');
url('/fonts/Lato-Bold.woff2') format('woff2'),
url('/fonts/Lato-Bold.woff') format('woff');
font-weight: bold;
font-style: normal;
font-display: swap;
@@ -29,8 +29,8 @@ $accentColor: #e4c428;
@font-face {
font-family: 'Lato';
src:
url('$fonts/Lato-Regular.woff2') format('woff2'),
url('$fonts/Lato-Regular.woff') format('woff');
url('/fonts/Lato-Regular.woff2') format('woff2'),
url('/fonts/Lato-Regular.woff') format('woff');
font-weight: normal;
font-style: normal;
font-display: swap;
+6 -3
View File
@@ -8,6 +8,7 @@ export interface IStore {
chosenVehicle: Vehicle | null;
isColdStart: boolean;
isDoubleManned: boolean;
showSupporter: boolean;
imageLoading: boolean;
@@ -41,7 +42,9 @@ export interface IStockProps {
type: string;
length: number;
mass: number;
cargo: string;
cargo?: string | null;
coldStart?: boolean;
doubleManned?: boolean;
}
export interface IStockData {
@@ -64,8 +67,6 @@ export interface IStockData {
};
props: IStockProps[];
usage: { [key: string]: string };
}
export interface ILocomotive {
@@ -81,6 +82,8 @@ export interface ILocomotive {
mass: number;
length: number;
coldStart: boolean;
doubleManned: boolean;
}
export interface ICarWagon {
-7
View File
@@ -1,7 +0,0 @@
const supportedConstructions = ["303e", "203e"];
export function locoSupportsColdStart(constructionType: string) {
return new RegExp(`(${supportedConstructions.join("|")})`).test(
constructionType,
);
}
-19
View File
@@ -1,19 +0,0 @@
import speedLimitTable from "../constants/speedLimits.json";
export type LocoType = keyof typeof speedLimitTable;
export const calculateSpeedLimit = (
locoType: LocoType,
stockMass: number,
isTrainPassenger: boolean,
) => {
const speedTable =
speedLimitTable[locoType][isTrainPassenger ? "passenger" : "cargo"];
if (!speedTable) return undefined;
let speedLimit = 0;
for (const mass in speedTable)
if (stockMass > Number(mass)) speedLimit = (speedTable as any)[mass];
return speedLimit;
};
+22
View File
@@ -0,0 +1,22 @@
import speedLimits from '../constants/speedLimits.json';
import massLimits from '../constants/massLimits.json';
export type SpeedLimitLocoType = keyof typeof speedLimits;
export type MassLimitLocoType = keyof typeof massLimits;
export function calculateSpeedLimit(locoType: SpeedLimitLocoType, stockMass: number, isTrainPassenger: boolean) {
const speedTable = speedLimits[locoType][isTrainPassenger ? 'passenger' : 'cargo'];
if (!speedTable) return undefined;
let speedLimit = 0;
for (const mass in speedTable) if (stockMass > Number(mass)) speedLimit = (speedTable as any)[mass];
return speedLimit;
}
export function calculateMassLimit(locoType: MassLimitLocoType, isTrainPassenger: boolean) {
if(massLimits[locoType] === undefined) return 0;
return massLimits[locoType][isTrainPassenger ? 0 : 1] || 0;
}
+14 -27
View File
@@ -1,6 +1,6 @@
import { EVehicleUseType } from '../enums/EVehicleUseType';
import { ICarWagon, ILocomotive, IStore, TCarWagonGroup, TLocoGroup } from '../types';
import { LocoType, calculateSpeedLimit } from './speedLimitUtils';
import { MassLimitLocoType, SpeedLimitLocoType, calculateMassLimit, calculateSpeedLimit } from './vehicleLimitsUtils';
export function isLocomotive(vehicle: ILocomotive | ICarWagon): vehicle is ILocomotive {
return (vehicle as ILocomotive).power !== undefined;
@@ -33,8 +33,11 @@ export function locoDataList(state: IStore) {
sponsorsOnlyTimestamp: Number(sponsorsTimestamp),
imageSrc: '',
length: locoProps?.length && type.startsWith('2EN') ? locoProps.length * 2 : locoProps?.length || 0,
mass: locoProps?.mass && type.startsWith('2EN') ? 253 : locoProps?.mass || 0,
length: locoProps?.length && type.startsWith('2EN') ? locoProps.length * 2 : locoProps?.length ?? 0,
mass: locoProps?.mass && type.startsWith('2EN') ? 253 : locoProps?.mass ?? 0,
coldStart: locoProps?.coldStart ?? false,
doubleManned: locoProps?.doubleManned ?? false,
});
});
@@ -70,12 +73,10 @@ export function carDataList(state: IStore) {
maxSpeed: Number(maxSpeed),
imageSrc: '',
cargoList:
!carPropsData || carPropsData.cargo === null
? []
: carPropsData.cargo.split(';').map((cargo) => ({
id: cargo.split(':')[0],
totalMass: Number(cargo.split(':')[1]),
})),
carPropsData?.cargo?.split(';').map((cargo) => ({
id: cargo.split(':')[0],
totalMass: Number(cargo.split(':')[1]),
})) || [],
mass: carPropsData?.mass || 0,
length: carPropsData?.length || 0,
@@ -106,33 +107,19 @@ export function maxStockSpeed(state: IStore) {
const stockMass = totalMass(state);
const speedLimitByMass = calculateSpeedLimit(locoType as LocoType, stockMass, isTrainPassenger(state));
const speedLimitByMass = calculateSpeedLimit(locoType as SpeedLimitLocoType, stockMass, isTrainPassenger(state));
return speedLimitByMass ? Math.min(stockSpeedLimit, speedLimitByMass) : stockSpeedLimit;
}
export function acceptableMass(state: IStore) {
if (state.stockList.length == 0 || !state.stockList[0].isLoco) return 0;
const activeLocomotiveType = state.stockList[0].type;
if (/^SM/.test(activeLocomotiveType)) return 2400;
const activeLocomotiveType = state.stockList[0].type.split('-')[0];
// Elektryczne EU07 / EP07 / EP08 / ET41
const locoMassLimit = calculateMassLimit(activeLocomotiveType as MassLimitLocoType, isTrainPassenger(state));
// Pasażerski elektr.
if (isTrainPassenger(state)) {
if (/^(EU|EP)/.test(activeLocomotiveType)) return 650;
if (/^ET/.test(activeLocomotiveType)) return 700;
return 0;
}
// Towarowy / inny elektr.
if (/^EU/.test(activeLocomotiveType)) return 2000;
if (/^ET/.test(activeLocomotiveType)) return 4000;
if (/^EP/.test(activeLocomotiveType)) return 650;
return 0;
return locoMassLimit;
}
export function isTrainPassenger(state: IStore) {
+9 -10
View File
@@ -2,31 +2,29 @@ import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import { VitePWA } from 'vite-plugin-pwa';
import { resolve } from 'path';
// https://vitejs.dev/config/
export default defineConfig({
server: {
port: 2137,
},
resolve: {
alias: {
$fonts: resolve('/fonts'),
$images: resolve('/images'),
},
},
plugins: [
vue(),
VitePWA({
registerType: 'autoUpdate',
devOptions: {
suppressWarnings: true,
enabled: true,
},
workbox: {
globPatterns: ['**/*.{js,css,html,png,svg,img,woff,woff2}'],
globPatterns: ['**/*.{js,css,html,jpg,png,svg,img,woff,woff2}'],
runtimeCaching: [
{
urlPattern: /^https:\/\/rj.td2.info.pl\/dist\/img\/thumbnails\/.*/i,
handler: 'CacheFirst',
handler: 'NetworkFirst',
options: {
cacheName: 'swdr-images-cache',
expiration: {
@@ -40,10 +38,11 @@ export default defineConfig({
},
{
urlPattern: /^https:\/\/spythere.github.io\/api\/td2\/.*/i,
handler: 'CacheFirst',
handler: 'NetworkFirst',
options: {
cacheName: 'spythere-api-cache',
expiration: {
maxEntries: 150,
maxAgeSeconds: 60 * 60 * 24, // <== 1 day
},
cacheableResponse: {