mirror of
https://github.com/Spythere/pojazdownik.git
synced 2026-05-03 11:45:34 +00:00
359 lines
9.1 KiB
Vue
359 lines
9.1 KiB
Vue
<template>
|
|
<section class="wiki-list tab">
|
|
<div class="tab_header">
|
|
<h2>{{ $t('wiki.title') }}</h2>
|
|
</div>
|
|
|
|
<div class="tab_content">
|
|
<div class="actions-panel">
|
|
<div class="actions-panel_vehicles">
|
|
<button class="btn btn--choice" @click="changeWikiMode('locomotives')">
|
|
{{ $t('wiki.action-vehicles') }}
|
|
</button>
|
|
<button class="btn btn--choice" @click="changeWikiMode('carWagons')">
|
|
{{ $t('wiki.action-carriages') }}
|
|
</button>
|
|
</div>
|
|
|
|
<div class="actions-panel_search">
|
|
<input type="text" :placeholder="$t('wiki.search')" v-model="searchedVehicleTypeName" />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="table-wrapper" @scroll="scrollEvent" ref="table-wrapper">
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th v-for="header in wikiMode == 'locomotives' ? locoHeaders : carHeaders" @click="toggleSorter(header)" :key="header.id">
|
|
{{ $t(`wiki.header.${header.id}`) }}
|
|
|
|
<span v-if="currentModeSorter.id == header.id">
|
|
{{ currentModeSorter.direction == 1 ? `⇑` : `⇓` }}
|
|
</span>
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
|
|
<tbody v-if="wikiMode == 'locomotives'">
|
|
<tr
|
|
v-for="loco in computedLocoList"
|
|
:key="loco.type"
|
|
@click="previewLocomotive(loco)"
|
|
@keydown.enter="previewLocomotive(loco)"
|
|
@dblclick="addLocomotive(loco)"
|
|
tabindex="0"
|
|
>
|
|
<td>
|
|
<object :data="getThumbnailURL(loco.type, 'small')" type="image/jpeg">
|
|
<!-- <img src="default.jpg" /> -->
|
|
<div>?</div>
|
|
</object>
|
|
</td>
|
|
|
|
<td>{{ loco.type }}</td>
|
|
<td>{{ $t(`wiki.${loco.power}`) }}</td>
|
|
<td>{{ loco.constructionType }}</td>
|
|
<td>
|
|
{{ locoSupportsColdStart(loco.constructionType) ? `✓` : '✗' }}
|
|
</td>
|
|
<td>{{ loco.length }}m</td>
|
|
<td>{{ loco.mass }}t</td>
|
|
<td>{{ loco.maxSpeed }}km/h</td>
|
|
</tr>
|
|
</tbody>
|
|
|
|
<tbody v-else>
|
|
<tr
|
|
v-for="car in computedCarList"
|
|
:key="car.type"
|
|
@keydow.enter="previewCarWagon(car)"
|
|
@click="previewCarWagon(car)"
|
|
@dblclick="addCarWagon(car)"
|
|
tabindex="0"
|
|
>
|
|
<td>
|
|
<!-- <img
|
|
:src="getThumbnailURL(car.type, 'small')"
|
|
loading="lazy"
|
|
:alt="`${car.type}`"
|
|
/> -->
|
|
<object :data="getThumbnailURL(car.type, 'small')" type="image/jpeg" loading="lazy">
|
|
<!-- <img src="default.jpg" /> -->
|
|
<div>?</div>
|
|
</object>
|
|
</td>
|
|
|
|
<td>{{ car.type }}</td>
|
|
<td>{{ car.constructionType }}</td>
|
|
<td>{{ car.length }}m</td>
|
|
<td>{{ car.mass }}t</td>
|
|
<td>{{ car.maxSpeed }}km/h</td>
|
|
<td>
|
|
{{ car.cargoList.length == 0 ? '-' : car.cargoList.length }}
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { defineComponent } from 'vue';
|
|
import { useStore } from '../../store';
|
|
import stockPreviewMixin from '../../mixins/stockPreviewMixin';
|
|
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 WikiMode = 'locomotives' | 'carWagons';
|
|
type SorterID = 'type' | 'constructionType' | 'image' | 'length' | 'mass' | 'maxSpeed' | 'cargoCount' | 'power' | 'coldStart';
|
|
|
|
interface WikiHeader {
|
|
id: SorterID;
|
|
sortable: boolean;
|
|
}
|
|
|
|
const locoHeaders: WikiHeader[] = [
|
|
{ id: 'image', sortable: false },
|
|
{ id: 'type', sortable: true },
|
|
{ id: 'power', sortable: true },
|
|
{ id: 'constructionType', sortable: true },
|
|
{ id: 'coldStart', sortable: true },
|
|
{ id: 'length', sortable: true },
|
|
{ id: 'mass', sortable: true },
|
|
{ id: 'maxSpeed', sortable: true },
|
|
];
|
|
|
|
const carHeaders: WikiHeader[] = [
|
|
{ id: 'image', sortable: false },
|
|
{ id: 'type', sortable: true },
|
|
{ id: 'constructionType', sortable: true },
|
|
{ id: 'length', sortable: true },
|
|
{ id: 'mass', sortable: true },
|
|
{ id: 'maxSpeed', sortable: true },
|
|
{ id: 'cargoCount', sortable: true },
|
|
];
|
|
|
|
export default defineComponent({
|
|
mixins: [stockPreviewMixin, stockMixin, imageMixin],
|
|
|
|
data() {
|
|
return {
|
|
store: useStore(),
|
|
locoHeaders,
|
|
carHeaders,
|
|
|
|
locosScrollTop: 0,
|
|
carsScrollTop: 0,
|
|
|
|
wikiMode: 'locomotives' as WikiMode,
|
|
searchedVehicleTypeName: '',
|
|
|
|
currentLocoSorter: {
|
|
id: 'type' as SorterID,
|
|
direction: 1,
|
|
},
|
|
|
|
currentCarSorter: {
|
|
id: 'type' as SorterID,
|
|
direction: 1,
|
|
},
|
|
};
|
|
},
|
|
|
|
activated() {
|
|
const tableWrapperRef = this.$refs['table-wrapper'] as HTMLElement;
|
|
tableWrapperRef.scrollTo({
|
|
top: this.wikiMode == 'locomotives' ? this.locosScrollTop : this.carsScrollTop,
|
|
});
|
|
},
|
|
|
|
methods: {
|
|
locoSupportsColdStart,
|
|
|
|
scrollEvent(e: Event) {
|
|
const tableScrollTop = (e.target as HTMLElement).scrollTop;
|
|
|
|
if (this.wikiMode == 'locomotives') this.locosScrollTop = tableScrollTop;
|
|
else this.carsScrollTop = tableScrollTop;
|
|
},
|
|
|
|
changeWikiMode(wikiMode: WikiMode) {
|
|
this.searchedVehicleTypeName = '';
|
|
this.wikiMode = wikiMode;
|
|
},
|
|
|
|
toggleSorter(header: WikiHeader) {
|
|
if (!header.sortable) return;
|
|
|
|
if (header.id == this.currentModeSorter.id) this.currentModeSorter.direction *= -1;
|
|
this.currentModeSorter.id = header.id;
|
|
},
|
|
|
|
sortVehicles(vA: Vehicle, vB: Vehicle) {
|
|
const { id, direction } = this.currentModeSorter;
|
|
const vehiclesAreLocos = isLocomotive(vA) && isLocomotive(vB);
|
|
const vehiclesAreCars = !isLocomotive(vA) && !isLocomotive(vB);
|
|
|
|
switch (id) {
|
|
case 'type':
|
|
case 'constructionType':
|
|
return direction == 1 ? vA[id].localeCompare(vB[id]) : vB[id].localeCompare(vA[id]);
|
|
|
|
case 'mass':
|
|
case 'length':
|
|
case 'maxSpeed':
|
|
return Math.sign(vA[id] - vB[id]) * direction;
|
|
|
|
case 'cargoCount':
|
|
if (vehiclesAreCars) return Math.sign((vA.cargoList.length || -1) - (vB.cargoList.length || -1)) * direction;
|
|
break;
|
|
|
|
case 'coldStart':
|
|
if (vehiclesAreLocos) return (locoSupportsColdStart(vA.constructionType) > locoSupportsColdStart(vB.constructionType) ? 1 : -1) * direction;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return direction == 1 ? vA.type.localeCompare(vB.type) : vB.type.localeCompare(vA.type);
|
|
},
|
|
},
|
|
|
|
computed: {
|
|
currentModeSorter() {
|
|
return this.wikiMode == 'carWagons' ? this.currentCarSorter : this.currentLocoSorter;
|
|
},
|
|
|
|
computedLocoList() {
|
|
const trimmedSearchValue = this.searchedVehicleTypeName.trim();
|
|
|
|
return this.store.locoDataList.filter((loco) => new RegExp(`${trimmedSearchValue}`, 'i').test(loco.type)).sort(this.sortVehicles);
|
|
},
|
|
|
|
computedCarList() {
|
|
const trimmedSearchValue = this.searchedVehicleTypeName.trim();
|
|
|
|
return this.store.carDataList.filter((car) => new RegExp(`${trimmedSearchValue}`, 'i').test(car.type)).sort(this.sortVehicles);
|
|
},
|
|
},
|
|
});
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
@import '../../styles/tab.scss';
|
|
|
|
.actions-panel {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
|
|
flex-wrap: wrap;
|
|
gap: 0.5em;
|
|
|
|
margin: 0.5em 0;
|
|
}
|
|
|
|
.actions-panel_vehicles {
|
|
display: flex;
|
|
gap: 0.5em;
|
|
}
|
|
|
|
.actions-panel_search {
|
|
input {
|
|
width: auto;
|
|
}
|
|
}
|
|
|
|
.table-wrapper {
|
|
overflow: auto;
|
|
height: 750px;
|
|
max-height: 95vh;
|
|
}
|
|
|
|
.wiki-list table {
|
|
border-collapse: collapse;
|
|
width: 100%;
|
|
|
|
thead {
|
|
position: sticky;
|
|
top: 0;
|
|
}
|
|
|
|
th {
|
|
background-color: #111;
|
|
padding: 0.5em;
|
|
user-select: none;
|
|
-moz-user-select: none;
|
|
-webkit-user-select: none;
|
|
}
|
|
|
|
tr {
|
|
cursor: pointer;
|
|
background-color: #333;
|
|
|
|
&:nth-child(odd) {
|
|
background-color: #444;
|
|
}
|
|
|
|
&:hover {
|
|
background-color: #666;
|
|
}
|
|
}
|
|
|
|
td {
|
|
text-align: center;
|
|
padding: 0.25em;
|
|
height: 85px;
|
|
}
|
|
|
|
td:first-child {
|
|
width: 120px;
|
|
}
|
|
|
|
td object[type='image/jpeg'] {
|
|
display: flex;
|
|
max-width: 120px;
|
|
min-height: 60px;
|
|
|
|
div {
|
|
margin: auto;
|
|
}
|
|
}
|
|
}
|
|
|
|
@media screen and (max-width: $breakpointMd) {
|
|
.wiki-list table {
|
|
td {
|
|
width: 100px;
|
|
height: auto;
|
|
|
|
img {
|
|
width: 6em;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@media screen and (max-width: $breakpointSm) {
|
|
.actions-panel {
|
|
align-items: stretch;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.actions-panel_vehicles {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
}
|
|
|
|
.actions-panel_search {
|
|
display: grid;
|
|
}
|
|
}
|
|
</style>
|