mirror of
https://github.com/Spythere/pojazdownik.git
synced 2026-05-03 05:18:10 +00:00
feat: loading data from clipboard; error detection
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
<LogoSection />
|
||||
<InputsSection />
|
||||
<TrainImageSection />
|
||||
<StockSection />
|
||||
<TabsSection />
|
||||
</main>
|
||||
</template>
|
||||
|
||||
@@ -12,10 +12,10 @@ import { defineComponent } from 'vue';
|
||||
import LogoSection from '../sections/LogoSection.vue';
|
||||
import InputsSection from '../sections/InputsSection.vue';
|
||||
import TrainImageSection from '../sections/TrainImageSection.vue';
|
||||
import StockSection from '../sections/StockSection.vue';
|
||||
import TabsSection from '../sections/TabsSection.vue';
|
||||
|
||||
export default defineComponent({
|
||||
components: { LogoSection, InputsSection, TrainImageSection, StockSection },
|
||||
components: { LogoSection, InputsSection, TrainImageSection, TabsSection },
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
+33
-13
@@ -1,9 +1,17 @@
|
||||
<template>
|
||||
<section class="stock-section">
|
||||
<div class="section_modes">
|
||||
<router-link v-for="(route, i) in routes" :key="route.name" class="link-btn" :to="route.href">
|
||||
<section class="tabs-section">
|
||||
<div class="tabs-modes">
|
||||
<router-link
|
||||
v-for="(route, i) in routes"
|
||||
:key="route.name"
|
||||
class="link-btn"
|
||||
:to="route.href"
|
||||
:style="{ 'grid-area': route.name }"
|
||||
>
|
||||
<span class="text--accent">{{ i + 1 }}.</span> {{ $t(`topbar.${route.name}`) }}
|
||||
<span class="text--grayed" v-if="route.name == 'stock'">({{ store.stockList.length }})</span>
|
||||
<span class="text--grayed" v-if="route.name == 'stock'"
|
||||
>({{ store.stockList.length }})</span
|
||||
>
|
||||
</router-link>
|
||||
</div>
|
||||
|
||||
@@ -33,6 +41,10 @@ const routes = [
|
||||
name: 'wiki',
|
||||
href: '/wiki',
|
||||
},
|
||||
{
|
||||
name: 'storage',
|
||||
href: '/storage',
|
||||
},
|
||||
{
|
||||
name: 'numgen',
|
||||
href: '/numgen',
|
||||
@@ -47,7 +59,7 @@ onMounted(() => {
|
||||
window.addEventListener('keydown', (e) => {
|
||||
if (e.target instanceof HTMLInputElement) return;
|
||||
|
||||
if (/^[1234]$/.test(e.key)) {
|
||||
if (/^[12345]$/.test(e.key)) {
|
||||
const keyNum = Number(e.key);
|
||||
|
||||
router.push(routes[keyNum - 1].href);
|
||||
@@ -57,8 +69,6 @@ onMounted(() => {
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
|
||||
// Tab change animation
|
||||
.tab-change {
|
||||
&-enter-from,
|
||||
@@ -73,7 +83,7 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
// Section styles
|
||||
.stock-section {
|
||||
.tabs-section {
|
||||
grid-row: 1 / 4;
|
||||
grid-column: 2;
|
||||
|
||||
@@ -81,9 +91,13 @@ onMounted(() => {
|
||||
padding: 1px;
|
||||
}
|
||||
|
||||
.section_modes {
|
||||
.tabs-modes {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
grid-template-areas:
|
||||
'stock stock wiki wiki storage storage'
|
||||
'numgen numgen numgen stockgen stockgen stockgen';
|
||||
grid-template-columns: repeat(6, 1fr);
|
||||
// grid-template-rows: 1fr 1fr;
|
||||
padding: 1px;
|
||||
|
||||
gap: 0.5em;
|
||||
@@ -91,9 +105,15 @@ onMounted(() => {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 650px) {
|
||||
.section_modes {
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||
@media screen and (max-width: 400px) {
|
||||
.tabs-modes {
|
||||
grid-template-areas:
|
||||
'stock wiki'
|
||||
'storage storage'
|
||||
'numgen stockgen';
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
|
||||
// grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -224,8 +224,7 @@ const randomizeTrainNumber = (randomizeRegions = false) => {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
|
||||
@use '../../styles/tab';
|
||||
|
||||
.category-select {
|
||||
select {
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
<template>
|
||||
<div class="stock-generator tab">
|
||||
<div class="tab_header">
|
||||
<h2>{{ $t('stockgen.title') }}</h2>
|
||||
</div>
|
||||
|
||||
<div class="tab_content">
|
||||
<div>
|
||||
<h2>{{ $t('stockgen.properties-title') }}</h2>
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
<template>
|
||||
<section class="stock-list-tab">
|
||||
<div class="tab_header">
|
||||
<h2>{{ $t('stocklist.title') }}</h2>
|
||||
</div>
|
||||
|
||||
<div class="tab_content">
|
||||
<div class="stock_actions">
|
||||
<button class="btn btn--image" @click="clickFileInput">
|
||||
<input type="file" @change="uploadStock" ref="conFile" accept=".con,.txt" />
|
||||
<input type="file" @change="uploadStockFromFile" ref="conFile" accept=".con,.txt" />
|
||||
<img src="/images/icon-upload.svg" alt="upload icon" />
|
||||
{{ $t('stocklist.action-upload') }}
|
||||
{{ $t('stocklist.action-upload-file') }}
|
||||
</button>
|
||||
|
||||
<button class="btn btn--image" @click="uploadStockFromClipboard">
|
||||
<img src="/images/icon-upload.svg" alt="upload icon" />
|
||||
{{ $t('stocklist.action-upload-clipboard') }}
|
||||
</button>
|
||||
|
||||
<button
|
||||
@@ -471,7 +472,7 @@ export default defineComponent({
|
||||
a.dispatchEvent(e);
|
||||
},
|
||||
|
||||
uploadStock() {
|
||||
uploadStockFromFile() {
|
||||
const inputEl = this.$refs['conFile'] as HTMLInputElement;
|
||||
const files = inputEl.files;
|
||||
|
||||
@@ -494,6 +495,23 @@ export default defineComponent({
|
||||
inputEl.value = '';
|
||||
},
|
||||
|
||||
async uploadStockFromClipboard() {
|
||||
try {
|
||||
const content = await navigator.clipboard.readText();
|
||||
this.loadStockFromString(content);
|
||||
} catch (error) {
|
||||
switch (error) {
|
||||
case 'stock-loading-error':
|
||||
alert(this.$t('stocklist.stock-loading-error'));
|
||||
break;
|
||||
|
||||
default:
|
||||
alert(this.$t('stocklist.stock-clipboard-error'));
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onDragStart(vehicleIndex: number) {
|
||||
this.draggedVehicleID = vehicleIndex;
|
||||
},
|
||||
@@ -521,7 +539,6 @@ export default defineComponent({
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@use '@/styles/tab';
|
||||
|
||||
.tab_content {
|
||||
@@ -571,7 +588,7 @@ export default defineComponent({
|
||||
display: grid;
|
||||
gap: 0.5em;
|
||||
|
||||
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
|
||||
button {
|
||||
width: 100%;
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<section class="tab storage-tab">
|
||||
<div class="tab_header">
|
||||
<h2>ZAPISANE SKŁADY</h2>
|
||||
<h3>Zarządzaj składami zapisanymi w pamięci przeglądarki</h3>
|
||||
</div>
|
||||
|
||||
<div class="tab_content">
|
||||
<div class="storage_actions">
|
||||
<!-- :data-disabled="stockIsEmpty"
|
||||
:disabled="stockIsEmpty"
|
||||
@click="downloadStock" -->
|
||||
<button
|
||||
class="btn btn--image"
|
||||
>
|
||||
<img src="/images/icon-download.svg" alt="download icon" />
|
||||
POBIERZ DO PLIKU
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="btn btn--image"
|
||||
>
|
||||
<img src="/images/icon-download.svg" alt="download icon" />
|
||||
SKOPIUJ DO SCHOWKA
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'storage-tab',
|
||||
|
||||
setup() {
|
||||
return {};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@use '@/styles/tab';
|
||||
</style>
|
||||
@@ -1,9 +1,5 @@
|
||||
<template>
|
||||
<section class="wiki-list tab">
|
||||
<div class="tab_header">
|
||||
<h2>{{ $t('wiki.title') }}</h2>
|
||||
</div>
|
||||
|
||||
<div class="tab_content">
|
||||
<div class="actions">
|
||||
<div class="action action-input">
|
||||
|
||||
+8
-14
@@ -57,9 +57,10 @@
|
||||
"action-move-up": "MOVE UP",
|
||||
"action-move-down": "MOVE DOWN",
|
||||
"action-remove": "REMOVE",
|
||||
"action-upload": "LOAD",
|
||||
"action-download": "DOWNLOAD",
|
||||
"action-copy": "COPY",
|
||||
"action-upload-file": "LOAD FILE",
|
||||
"action-upload-clipboard": "LOAD CLIPBOARD",
|
||||
"action-download": "DOWNLOAD TO FILE",
|
||||
"action-copy": "COPY TO CLIPBOARD",
|
||||
"action-reset": "RESET",
|
||||
"action-shuffle": "SHUFFLE",
|
||||
"mass": "Mass",
|
||||
@@ -69,14 +70,15 @@
|
||||
"coldstart-info": "Locomotive cold start",
|
||||
"doublemanning-info": "Double manning",
|
||||
"list-empty": "Stock list is empty!",
|
||||
|
||||
"warning-not-suitable": "EP series locomotives are designed for passenger traffic only!",
|
||||
"warning-passenger-too-long": "Maximum length of a passenger train may not be greater than 350m!",
|
||||
"warning-freight-too-long": "Maximum length of a freight train may not be greater than 650m!",
|
||||
"warning-too-many-locos": "This train has too many traction units!",
|
||||
"warning-too-heavy": "This train is too heavy! Check {href}",
|
||||
"warning-team-only-vehicle": "There's at least one vehicle available only for TD2 team members in your stock composition! ({0})",
|
||||
"acceptable-mass-docs": "acceptable rolling stock masses (PL)"
|
||||
"acceptable-mass-docs": "acceptable rolling stock masses (PL)",
|
||||
"stock-loading-error": "An error occurred: cannot parse data from the file - make sure it's in a proper format!",
|
||||
"stock-clipboard-error": "An error occurred: cannot read data from the clipboard - make sure the site has been granted right permissions for this action!"
|
||||
},
|
||||
"stockgen": {
|
||||
"title": "FREIGHT TRAIN GENERATOR",
|
||||
@@ -108,7 +110,6 @@
|
||||
"action-random-region": "DRAW REGIONS",
|
||||
"action-random-number": "DRAW LAST DIGITS",
|
||||
"action-random-category": "DRAW A CATEGORY",
|
||||
|
||||
"rules": {
|
||||
"first-digit": "First digit:",
|
||||
"second-digit": "Second digit:",
|
||||
@@ -123,25 +124,20 @@
|
||||
"for-region-end": "for the terminating construction region",
|
||||
"from-range": "from range of"
|
||||
},
|
||||
|
||||
"categories": {
|
||||
"EI": "EI - domestic express",
|
||||
"EC": "EC - international express",
|
||||
"EN": "EN - domestic night express",
|
||||
|
||||
"MP": "MP - intervoivodeship bullet",
|
||||
"MO": "MO - intervoivodeship regio",
|
||||
"MM": "MM - international bullet",
|
||||
"MH": "MH - intervoivodeship night bullet",
|
||||
|
||||
"RP": "RP - voivodeship bullet",
|
||||
"RM": "RM - international voivodeship regio",
|
||||
"RO": "RO - voivodeship regio",
|
||||
"RA": "RA - voivodeship regio (urban)",
|
||||
|
||||
"PW": "PW - empty passenger",
|
||||
"PX": "PX - empty passenger test drive",
|
||||
|
||||
"TC": "TC - international freight (intermodal)",
|
||||
"TG": "TG - international freight (organized cargo)",
|
||||
"TR": "TR - international freight (unorganized cargo)",
|
||||
@@ -151,12 +147,10 @@
|
||||
"TK": "TK - freight (for stations & sidings)",
|
||||
"TS": "TS - empty freight test drive",
|
||||
"TH": "TH - locomotive rolling stock (over 3 vehicles)",
|
||||
|
||||
"LT": "LT - freight locomotive only",
|
||||
"LP": "LP - passenger locomotive only",
|
||||
"LS": "LS - shunting locomotive only",
|
||||
"LZ": "LS - shunting locomotive only",
|
||||
|
||||
"ZN": "ZN - inspection / diagnostic type",
|
||||
"ZU": "ZU - other maintenance type"
|
||||
}
|
||||
@@ -313,4 +307,4 @@
|
||||
"418Vb_ZOS": "loose cargo (sand, stone)",
|
||||
"418Vb_ZUE": "loose cargo (sand, stone)"
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
-15
@@ -44,7 +44,8 @@
|
||||
"stock": "SKŁAD",
|
||||
"wiki": "POJAZDY",
|
||||
"numgen": "GNR NUMERU",
|
||||
"stockgen": "GNR SKŁADU"
|
||||
"stockgen": "GNR SKŁADU",
|
||||
"storage": "ZAPISANE SKŁADY"
|
||||
},
|
||||
"stocklist": {
|
||||
"title": "EDYTOR SKŁADU",
|
||||
@@ -57,9 +58,10 @@
|
||||
"action-move-up": "PRZENIEŚ WYŻEJ",
|
||||
"action-move-down": "PRZENIEŚ NIŻEJ",
|
||||
"action-remove": "USUŃ",
|
||||
"action-upload": "WCZYTAJ",
|
||||
"action-download": "POBIERZ",
|
||||
"action-copy": "SKOPIUJ",
|
||||
"action-upload-file": "WCZYTAJ (PLIK)",
|
||||
"action-upload-clipboard": "WCZYTAJ (SCHOWEK)",
|
||||
"action-download": "POBIERZ DO PLIKU",
|
||||
"action-copy": "SKOPIUJ DO SCHOWKA",
|
||||
"action-reset": "ZRESETUJ",
|
||||
"action-shuffle": "PRZETASUJ",
|
||||
"mass": "Masa",
|
||||
@@ -69,14 +71,15 @@
|
||||
"coldstart-info": "Zimny start",
|
||||
"doublemanning-info": "Podwójna obsada",
|
||||
"list-empty": "Lista pojazdów jest pusta!",
|
||||
|
||||
"warning-not-suitable": "Lokomotywy serii EP są przeznaczone jedynie do ruchu pasażerskiego!",
|
||||
"warning-passenger-too-long": "Maksymalna długość składów pasażerskich nie może przekraczać 350m!",
|
||||
"warning-freight-too-long": "Maksymalna długość składów innych niż pasażerskie nie może przekraczać 650m!",
|
||||
"warning-too-many-locos": "Ten skład posiada za dużo pojazdów trakcyjnych!",
|
||||
"warning-too-heavy": "Ten skład jest za ciężki! Sprawdź {href}",
|
||||
"warning-team-only-vehicle": "W zestawieniu znajduje się co najmniej jeden pojazd dostępny tylko dla członków zespołu TD2! ({0})",
|
||||
"acceptable-mass-docs": "dopuszczalne masy składów"
|
||||
"acceptable-mass-docs": "dopuszczalne masy składów",
|
||||
"stock-loading-error": "Wystąpił błąd: nie można przetworzyć danych ze schowka! Upewnij się, że są one w poprawnym formacie!",
|
||||
"stock-clipboard-error": "Wystąpił błąd: nie można odczytać danych ze schowka! Upewnij się, że nadałeś uprawnienia stronie do tej akcji!"
|
||||
},
|
||||
"stockgen": {
|
||||
"title": "GENERATOR SKŁADU TOWAROWEGO",
|
||||
@@ -108,7 +111,6 @@
|
||||
"action-random-region": "LOSUJ OBSZARY",
|
||||
"action-random-number": "LOSUJ KOŃCÓWKĘ",
|
||||
"action-random-category": "LOSUJ KATEGORIĘ",
|
||||
|
||||
"rules": {
|
||||
"first-digit": "Pierwsza cyfra:",
|
||||
"second-digit": "Druga cyfra:",
|
||||
@@ -123,25 +125,20 @@
|
||||
"for-region-end": "dla końcowego obszaru konstrukcyjnego",
|
||||
"from-range": "z przedziału"
|
||||
},
|
||||
|
||||
"categories": {
|
||||
"EI": "EI - ekspres krajowy",
|
||||
"EC": "EC - ekspres międzynarodowy",
|
||||
"EN": "EN - ekspres krajowy nocny",
|
||||
|
||||
"MP": "MP - międzywoj. pośpieszny",
|
||||
"RP": "RP - wojewódzki pośpieszny",
|
||||
"MO": "MO - międzywoj. osobowy",
|
||||
"RO": "RO - wojewódzki osobowy",
|
||||
|
||||
"MM": "MM - międzynar. pośpieszny",
|
||||
"MH": "MH - międzywoj. pośpieszny hotelowy",
|
||||
"RM": "RM - woj. osobowy międzynarodowy",
|
||||
"RA": "RA - woj. osobowy aglomeracyjny",
|
||||
|
||||
"PW": "PW - pasażerski próżny - służbowy",
|
||||
"PX": "PX - pasażerski próżny próbny",
|
||||
|
||||
"TC": "TC - towarowy międzynarodowy intermodalny",
|
||||
"TG": "TG - towarowy międzynarodowy masowy",
|
||||
"TR": "TR - towarowy międzynarodowy niemasowy",
|
||||
@@ -151,12 +148,10 @@
|
||||
"TK": "TK - towarowy (stacje i bocznice)",
|
||||
"TS": "TS - towarowy próżny próbny",
|
||||
"TH": "TH - skład lokomotyw (powyżej 3 pojazdów)",
|
||||
|
||||
"LT": "LT - lokomotywa towarowa luzem",
|
||||
"LP": "LP - lokomotywa pasażerska luzem",
|
||||
"LS": "LS - lokomotywa manewrowa luzem",
|
||||
"LZ": "LZ - lokomotywa dla poc. utrzymaniowo-naprawczych",
|
||||
|
||||
"ZN": "ZN - inspekcyjny / diagnostyczny",
|
||||
"ZU": "ZU - inny utrzymaniowy"
|
||||
}
|
||||
@@ -312,4 +307,4 @@
|
||||
"418Vb_ZOS": "drobnica, ładunki sypkie (piasek, kamień)",
|
||||
"418Vb_ZUE": "drobnica, ładunki sypkie (piasek, kamień)"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,6 +53,7 @@ export default defineComponent({
|
||||
|
||||
loadStockFromString(stockString: string) {
|
||||
const stockArray = stockString.trim().split(';');
|
||||
let failureCount = 0;
|
||||
|
||||
this.store.stockList.length = 0;
|
||||
this.store.chosenVehicle = null;
|
||||
@@ -85,10 +86,19 @@ export default defineComponent({
|
||||
if (cargo) vehicleCargo = vehicle?.cargoTypes.find((c) => c.id == cargo) || null;
|
||||
}
|
||||
|
||||
if (!vehicle) console.warn('Brak pojazdu / rodzaj pojazdu źle wczytany:', type);
|
||||
if (!vehicle && type) {
|
||||
failureCount++;
|
||||
console.warn(`Wystąpił błąd - nie wczytano pojazdu o nazwie: ${type}`);
|
||||
return;
|
||||
}
|
||||
|
||||
this.addVehicle(vehicle, vehicleCargo);
|
||||
});
|
||||
|
||||
if (failureCount != 0 && failureCount == stockArray.length) {
|
||||
console.warn('Wystąpił błąd - niepoprawny format');
|
||||
throw 'stock-loading-error';
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -4,6 +4,7 @@ import WikiListTab from './components/tabs/WikiListTab.vue';
|
||||
import StockListTab from './components/tabs/StockListTab.vue';
|
||||
import NumberGeneratorTab from './components/tabs/NumberGeneratorTab.vue';
|
||||
import StockGeneratorTab from './components/tabs/StockGeneratorTab.vue';
|
||||
import StorageTab from './components/tabs/StorageTab.vue';
|
||||
|
||||
const routes: RouteRecordRaw[] = [
|
||||
{
|
||||
@@ -41,6 +42,13 @@ const routes: RouteRecordRaw[] = [
|
||||
viewMode: StockGeneratorTab,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'storage',
|
||||
component: AppContainerView,
|
||||
meta: {
|
||||
viewMode: StorageTab,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -44,6 +44,8 @@ export const useStore = defineStore({
|
||||
stockList: [] as IStock[],
|
||||
cargoOptions: [] as any[][],
|
||||
|
||||
storageStockList: [] as IStock[][],
|
||||
|
||||
swapVehicles: false,
|
||||
|
||||
chosenStockListIndex: -1,
|
||||
|
||||
Reference in New Issue
Block a user