refactor: stock & vehicle typings

This commit is contained in:
2024-04-15 18:32:19 +02:00
parent 61c7f15fcf
commit 541572e415
13 changed files with 175 additions and 133 deletions
+3 -1
View File
@@ -42,7 +42,9 @@ main {
@media screen and (max-width: $breakpointMd) {
main {
display: block;
display: flex;
flex-direction: column;
gap: 1em;
}
}
</style>
+6 -6
View File
@@ -28,7 +28,8 @@
{{ $t('inputs.input-vehicle') }}
</option>
<option v-for="loco in locoOptions" :value="loco" :key="loco.type">
{{ loco.type }}<b v-if="loco.restrictions['sponsorOnly']">*</b>
{{ loco.type
}}<b v-if="loco.sponsorOnlyTimestamp && loco.sponsorOnlyTimestamp > Date.now()">*</b>
</option>
</select>
</div>
@@ -59,7 +60,8 @@
</option>
<option v-for="car in carOptions" :value="car" :key="car.type">
{{ car.type }}<b v-if="car.restrictions['sponsorOnly']">*</b>
{{ car.type
}}<b v-if="car.sponsorOnlyTimestamp && car.sponsorOnlyTimestamp > Date.now()">*</b>
</option>
</select>
</div>
@@ -84,6 +86,7 @@
<option :value="null" v-if="!store.chosenCar || !store.chosenCar.loadable">
{{ $t('inputs.no-cargo-available') }}
</option>
<option :value="null" v-else>{{ $t('inputs.cargo-empty') }}</option>
<option v-for="cargo in store.chosenCar?.cargoTypes" :value="cargo" :key="cargo.id">
@@ -193,10 +196,7 @@ export default defineComponent({
removeVehicle() {
if (this.store.stockList.length == 0) return;
const lastStock = this.store.stockList.slice(-1)[0];
if (lastStock.count > 1) lastStock.count--;
else this.store.stockList.splice(-1);
this.store.stockList.splice(-1);
},
switchVehicles() {
+30 -14
View File
@@ -4,8 +4,11 @@
<img
:src="getThumbnailURL(store.chosenVehicle.type, 'small')"
:data-preview-active="store.chosenVehicle !== null"
:data-sponsor-only="store.chosenVehicle?.restrictions.sponsorOnly"
:data-team-only="store.chosenVehicle?.restrictions.teamOnly"
:data-sponsor-only="
store.chosenVehicle.sponsorOnlyTimestamp &&
store.chosenVehicle.sponsorOnlyTimestamp > Date.now()
"
:data-team-only="store.chosenVehicle.teamOnly"
@click="onImageClick"
@keydown.enter="onImageClick"
@error="onImageError"
@@ -41,17 +44,23 @@
}}
</div>
<b v-if="store.chosenVehicle.restrictions.sponsorOnly > 0" class="sponsor-only">{{
$t('preview.sponsor-only', [
new Date(store.chosenVehicle.restrictions['sponsorOnly']).toLocaleDateString(
$i18n.locale == 'pl' ? 'pl-PL' : 'en-GB'
),
])
}}</b>
<b
v-if="
store.chosenVehicle.sponsorOnlyTimestamp &&
store.chosenVehicle.sponsorOnlyTimestamp > Date.now()
"
class="sponsor-only"
>
{{
$t('preview.sponsor-only', [
new Date(store.chosenVehicle.sponsorOnlyTimestamp).toLocaleDateString(
$i18n.locale == 'pl' ? 'pl-PL' : 'en-GB'
),
])
}}
</b>
<b v-if="store.chosenVehicle.restrictions['teamOnly']" class="team-only">{{
$t('preview.team-only')
}}</b>
<b v-if="store.chosenVehicle.teamOnly" class="team-only">{{ $t('preview.team-only') }}</b>
</div>
</div>
</div>
@@ -120,8 +129,7 @@ export default defineComponent({
align-items: center;
text-align: center;
margin-top: 1em;
height: 250px;
min-height: 250px;
& > div {
max-width: 100%;
@@ -152,6 +160,14 @@ img {
background-color: $bgColor;
}
.sponsor-only {
color: $sponsorColor;
}
.team-only {
color: $teamColor;
}
.image-info {
font-size: 1.1em;
padding: 0.5em;
+8 -3
View File
@@ -119,6 +119,7 @@ import { useStore } from '../../store';
import stockMixin from '../../mixins/stockMixin';
import { ICargo, ICarWagon, IStock } from '../../types';
import { isTractionUnit } from '../../utils/vehicleUtils';
export default defineComponent({
name: 'stock-generator',
@@ -186,8 +187,8 @@ export default defineComponent({
if (!this.isCarGroupingEnabled) return false;
stockList.sort((s1, s2) => {
return (s1.constructionType + s1.cargo?.id).localeCompare(
s2.constructionType + s2.cargo?.id
return (s1.vehicleRef.constructionType + s1.cargo?.id).localeCompare(
s2.vehicleRef.constructionType + s2.cargo?.id
);
});
},
@@ -238,7 +239,11 @@ export default defineComponent({
};
for (let i = 0; i < 10; i++) {
this.store.stockList.splice(this.store.stockList[0]?.isLoco ? 1 : 0);
this.store.stockList.splice(
this.store.stockList.length > 0 && isTractionUnit(this.store.stockList[0].vehicleRef)
? 1
: 0
);
let carCount = 0;
const maxWeight =
+33 -32
View File
@@ -132,7 +132,7 @@
(!)
{{
$t('stocklist.warning-team-only-vehicle', [
teamOnlyVehicles.map((v) => v.type).join(', '),
teamOnlyVehicles.map((v) => v.vehicleRef.type).join(', '),
])
}}
</div>
@@ -169,7 +169,7 @@
<li
v-for="(stock, i) in store.stockList"
:key="stock.id"
:class="{ loco: stock.isLoco }"
:class="{ loco: isTractionUnit(stock.vehicleRef) }"
tabindex="0"
@click="onListItemClick(i)"
@keydown.enter="onListItemClick(i)"
@@ -192,22 +192,29 @@
<span
class="stock-info-type"
:data-sponsor-only="stock.restrictions.sponsorOnly"
:data-team-only="stock.restrictions.teamOnly"
:data-sponsor-only="
stock.vehicleRef.sponsorOnlyTimestamp &&
stock.vehicleRef.sponsorOnlyTimestamp > Date.now()
"
:data-team-only="stock.vehicleRef.teamOnly"
>
{{ stock.isLoco ? stock.type : getCarSpecFromType(stock.type) }}
{{
isTractionUnit(stock.vehicleRef)
? stock.vehicleRef.type
: getCarSpecFromType(stock.vehicleRef.type)
}}
</span>
<span class="stock-info-cargo" v-if="stock.cargo">
{{ stock.cargo.id }}
</span>
<span class="stock-info-length">{{ stock.length }}m</span>
<span class="stock-info-length">{{ stock.vehicleRef.length }}m</span>
<span class="stock-info-mass">
{{ ((stock.weight + (stock.cargo?.weight ?? 0)) / 1000).toFixed(1) }}t
{{ ((stock.vehicleRef.weight + (stock.cargo?.weight ?? 0)) / 1000).toFixed(1) }}t
</span>
<span class="stock-info-speed">{{ stock.maxSpeed }}km/h</span>
<span class="stock-info-speed">{{ stock.vehicleRef.maxSpeed }}km/h</span>
</div>
</li>
</transition-group>
@@ -226,6 +233,7 @@ import stockPreviewMixin from '../../mixins/stockPreviewMixin';
import StockThumbnails from '../utils/StockThumbnails.vue';
import stockMixin from '../../mixins/stockMixin';
import Checkbox from '../common/Checkbox.vue';
import { isTractionUnit } from '../../utils/vehicleUtils';
export default defineComponent({
name: 'stock-list',
@@ -250,7 +258,7 @@ export default defineComponent({
computed: {
chosenRealComposition() {
const currentStockString = this.store.stockList.map((s) => s.type).join(';');
const currentStockString = this.store.stockList.map((s) => s.vehicleRef.type).join(';');
return this.store.realCompositionList.find((rc) => rc.stockString == currentStockString);
},
@@ -265,7 +273,9 @@ export default defineComponent({
return this.store.stockList
.map((stock, i) => {
let stockTypeStr =
stock.isLoco || !stock.cargo ? stock.type : `${stock.type}:${stock.cargo.id}`;
isTractionUnit(stock.vehicleRef) || !stock.cargo
? stock.vehicleRef.type
: `${stock.vehicleRef.type}:${stock.cargo.id}`;
if (i == 0 && (includeColdStart || includeDoubleManned))
return `${stockTypeStr},${includeColdStart ? 'c' : ''}${includeDoubleManned ? 'd' : ''}`;
@@ -300,22 +310,24 @@ export default defineComponent({
return (
!this.store.isTrainPassenger &&
this.store.stockList.length > 1 &&
!this.store.stockList.every((stock) => stock.isLoco) &&
this.store.stockList.some((stock) => stock.isLoco && stock.type.startsWith('EP'))
!this.store.stockList.every((stock) => isTractionUnit(stock.vehicleRef)) &&
this.store.stockList.some(
(stock) => isTractionUnit(stock.vehicleRef) && stock.vehicleRef.type.startsWith('EP')
)
);
},
locoCountExceeded() {
return (
this.store.stockList.reduce((acc, stock) => {
if (stock.isLoco) acc += stock.count;
if (isTractionUnit(stock.vehicleRef)) acc += 1;
return acc;
}, 0) > 2
);
},
teamOnlyVehicles() {
return this.store.stockList.filter((stock) => stock.restrictions.teamOnly);
return this.store.stockList.filter((stock) => stock.vehicleRef.teamOnly);
},
hasAnyWarnings() {
@@ -330,6 +342,8 @@ export default defineComponent({
},
methods: {
isTractionUnit,
copyToClipboard() {
navigator.clipboard.writeText(this.stockString);
@@ -346,7 +360,8 @@ export default defineComponent({
const stock = this.store.stockList[stockID];
this.store.chosenStockListIndex =
this.store.chosenStockListIndex == stockID && this.store.chosenVehicle?.type == stock.type
this.store.chosenStockListIndex == stockID &&
this.store.chosenVehicle?.type == stock.vehicleRef.type
? -1
: stockID;
@@ -377,20 +392,6 @@ export default defineComponent({
this.store.chosenStockListIndex = -1;
},
addStock(index: number) {
if (index == -1) return;
this.store.stockList[index].count++;
},
subStock(index: number) {
if (index == -1) return;
if (this.store.stockList[index].count < 2) return;
this.store.stockList[index].count--;
},
removeStock(index: number) {
if (index == -1) return;
@@ -424,7 +425,7 @@ export default defineComponent({
shuffleCars() {
const availableIndexes = this.store.stockList.reduce((acc, stock, i) => {
if (!stock.isLoco) acc.push(i);
if (!isTractionUnit(stock.vehicleRef)) acc.push(i);
return acc;
}, [] as number[]);
@@ -446,7 +447,7 @@ export default defineComponent({
downloadStock() {
if (this.store.stockList.length == 0) return alert(this.$t('stocklist.alert-empty'));
const defaultName = `${this.chosenRealComposition ? this.chosenRealComposition.stockId + ' ' : ''}${this.store.stockList[0].type} ${(this.store.totalWeight / 1000).toFixed(1)}t; ${
const defaultName = `${this.chosenRealComposition ? this.chosenRealComposition.stockId + ' ' : ''}${this.store.stockList[0].vehicleRef.type} ${(this.store.totalWeight / 1000).toFixed(1)}t; ${
this.store.totalLength
}m; vmax ${this.store.maxStockSpeed}`;
@@ -645,7 +646,7 @@ li > .stock-info {
color: $teamColor;
}
&[data-sponsor-only] {
&[data-sponsor-only='true'] {
color: $sponsorColor;
}
}
+26 -11
View File
@@ -48,8 +48,6 @@
v-for="vehicle in computedVehicles"
:key="vehicle.type"
:data-preview="vehicle.type === store.chosenVehicle?.type"
:data-sponsor-only="vehicle.restrictions.sponsorOnly > 0"
:data-team-only="vehicle.restrictions.teamOnly"
@click="previewVehicle(vehicle)"
@dblclick="addVehicle(vehicle)"
@keydown.enter="previewVehicle(vehicle)"
@@ -58,7 +56,16 @@
<img loading="lazy" width="120" :src="getThumbnailURL(vehicle.type, 'small')" />
<span>
<b class="vehicle-name"> {{ vehicle.type.replace(/_/g, ' ') }} </b>
<span
class="vehicle-name"
:class="{
'sponsor-only':
vehicle.sponsorOnlyTimestamp && vehicle.sponsorOnlyTimestamp > Date.now(),
'team-only': vehicle.teamOnly,
}"
>
<b>{{ vehicle.type.replace(/_/g, ' ') }}</b>
</span>
<div class="vehicle-group">
{{ $t(`wiki.${vehicle.group}`) }} |
@@ -238,14 +245,6 @@ export default defineComponent({
background-color: #435288;
}
&[data-sponsor-only='true'] {
box-shadow: 0 0 5px 0 $sponsorColor;
}
&[data-team-only='true'] {
box-shadow: 0 0 5px 0 $teamColor;
}
& > span {
display: flex;
flex-direction: column;
@@ -260,6 +259,22 @@ export default defineComponent({
text-overflow: ellipsis;
}
.sponsor-only {
color: $sponsorColor;
&::after {
content: '*';
}
}
.team-only {
color: $teamColor;
&::after {
content: '*';
}
}
.vehicle-props {
color: #ccc;
}
+17 -8
View File
@@ -5,7 +5,10 @@
v-for="(stock, stockIndex) in store.stockList"
:key="stockIndex"
:data-selected="store.chosenStockListIndex == stockIndex"
:data-sponsor="stock.restrictions.sponsorOnly"
:data-sponsor-only="
stock.vehicleRef.sponsorOnlyTimestamp && stock.vehicleRef.sponsorOnlyTimestamp > Date.now()
"
:data-team-only="stock.vehicleRef.teamOnly"
draggable="true"
@dragstart="onDragStart(stockIndex)"
@drop="onDrop($event, stockIndex)"
@@ -13,14 +16,14 @@
@click="onListItemClick(stockIndex)"
>
<b>
{{ stock.type }}
{{ stock.vehicleRef.type }}
</b>
<img
draggable="false"
:src="`https://rj.td2.info.pl/dist/img/thumbnails/${stock.type}.png`"
:alt="stock.type"
:title="stock.type"
:src="`https://rj.td2.info.pl/dist/img/thumbnails/${stock.vehicleRef.type}.png`"
:alt="stock.vehicleRef.type"
:title="stock.vehicleRef.type"
@error="stockImageError($event, stock)"
/>
</div>
@@ -43,7 +46,7 @@ const onListItemClick = (index: number) => {
};
const stockImageError = (e: Event, stock: IStock) => {
(e.target as HTMLImageElement).src = `images/${stock.group}-unknown.png`;
(e.target as HTMLImageElement).src = `images/${stock.vehicleRef.group}-unknown.png`;
};
watch(
@@ -88,6 +91,8 @@ const allowDrop = (e: DragEvent) => {
</script>
<style lang="scss" scoped>
@import '../../styles/global.scss';
.stock-thumbnails {
display: flex;
overflow: auto;
@@ -121,8 +126,12 @@ const allowDrop = (e: DragEvent) => {
margin: 0 1em;
}
&[data-sponsor='true'] > b {
color: salmon;
&[data-sponsor-only='true'] > b {
color: $sponsorColor;
}
&[data-team-only='true'] > b {
color: $teamColor;
}
img {