This commit is contained in:
2022-07-26 00:31:00 +02:00
parent bea95f9cf3
commit 451a184ccb
9 changed files with 149 additions and 159 deletions
+55 -21
View File
@@ -1,15 +1,24 @@
<template> <template>
<header>
<img :src="logoImage" alt="logo pojazdownik" />
</header>
<main>
<div class="image-preview" v-if="store.vehiclePreviewSrc != ''" @click="() => (store.vehiclePreviewSrc = '')"> <div class="image-preview" v-if="store.vehiclePreviewSrc != ''" @click="() => (store.vehiclePreviewSrc = '')">
<img :src="store.vehiclePreviewSrc" alt="preview" /> <img :src="store.vehiclePreviewSrc" alt="preview" />
</div> </div>
<div class="app_container">
<header>
<img :src="logoImage" alt="logo pojazdownik" />
</header>
<main>
<div id="inputs-area">
<InputsSection /> <InputsSection />
</div>
<div id="list-area">
<ListSection /> <ListSection />
</div>
<div id="image-area">
<TrainImage />
</div>
</main> </main>
<footer> <footer>
<div class="text--grayed" style="margin-bottom: 0.25em"> <div class="text--grayed" style="margin-bottom: 0.25em">
@@ -20,24 +29,26 @@
<a href="https://td2.info.pl/profile/?u=20777" target="_blank">Spythere</a> <a href="https://td2.info.pl/profile/?u=20777" target="_blank">Spythere</a>
{{ new Date().getUTCFullYear() }} | v{{ VERSION }} {{ new Date().getUTCFullYear() }} | v{{ VERSION }}
</footer> </footer>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
import packageInfo from '.././package.json'; import packageInfo from '.././package.json';
import { defineComponent, inject } from 'vue'; import { defineComponent } from 'vue';
import { IStore } from './types';
import InputsSection from './components/InputsSection.vue'; import InputsSection from './components/InputsSection.vue';
import ListSection from './components/ListSection.vue'; import ListSection from './components/ListSection.vue';
import logoImage from './assets/logo.svg'; import logoImage from './assets/logo.svg';
import { useStore } from './store'; import { useStore } from './store';
import TrainImage from './components/TrainImageSection.vue';
export default defineComponent({ export default defineComponent({
components: { components: {
ListSection, ListSection,
InputsSection, InputsSection,
TrainImage,
}, },
data: () => ({ data: () => ({
@@ -69,23 +80,22 @@ export default defineComponent({
<style lang="scss"> <style lang="scss">
@import './styles/global'; @import './styles/global';
.app_container {
min-height: 100vh;
display: flex;
flex-direction: column;
padding: 1em;
}
/* APP */ /* APP */
#app { #app {
margin: 0 auto; margin: 0 auto;
color: $textColor; color: $textColor;
min-height: 100vh; display: flex;
padding: 0.5em 1em;
overflow: hidden;
display: grid;
justify-content: center; justify-content: center;
grid-template-columns: minmax(200px, 1200px);
grid-template-rows: 5.5em 1fr auto;
} }
/* HEADER SECTION */ /* HEADER SECTION */
@@ -93,12 +103,11 @@ export default defineComponent({
header { header {
text-align: center; text-align: center;
margin-top: 1em;
img { img {
width: 35em; width: 35em;
} }
} }
h2 { h2 {
margin: 0; margin: 0;
margin-bottom: 0.5em; margin-bottom: 0.5em;
@@ -139,14 +148,39 @@ h2 {
/* MAIN SECTION */ /* MAIN SECTION */
main { main {
margin-top: 8em; margin-top: 2em;
display: grid;
gap: 1em 3em;
width: 100%;
max-width: 1200px;
grid-template-columns: 1fr 2fr;
grid-template-areas: 'inputs list' 'image list';
#inputs-area {
grid-area: inputs;
}
#list-area {
grid-area: list;
}
#image-area {
grid-area: image;
}
} }
/* FOOTER SECTION */
footer { footer {
margin-top: 1.5em; margin-top: auto;
text-align: center; text-align: center;
} }
/* MOBILE VIEWS */
@media screen and (max-width: 800px) { @media screen and (max-width: 800px) {
#app { #app {
font-size: calc(0.75vw + 0.6rem); font-size: calc(0.75vw + 0.6rem);
+22 -62
View File
@@ -5,7 +5,12 @@
<h2 class="input_header">WYBIERZ POJAZDY / WAGONY</h2> <h2 class="input_header">WYBIERZ POJAZDY / WAGONY</h2>
<div class="input_list type"> <div class="input_list type">
<select id="locomotives-list" v-model="store.chosenLoco"> <select
id="locomotives-list"
v-model="store.chosenLoco"
@focus="onVehicleSelect('loco')"
@input="onVehicleSelect('loco')"
>
<option :value="null" disabled>Wybierz pojazd trakcyjny</option> <option :value="null" disabled>Wybierz pojazd trakcyjny</option>
<option v-for="loco in locoOptions" :value="loco" :key="loco.type"> <option v-for="loco in locoOptions" :value="loco" :key="loco.type">
{{ loco.type }} {{ loco.type }}
@@ -16,7 +21,12 @@
</div> </div>
<div class="input_list type"> <div class="input_list type">
<select id="carwagons-list" v-model="store.chosenCar"> <select
id="carwagons-list"
v-model="store.chosenCar"
@focus="onVehicleSelect('car')"
@input="onVehicleSelect('car')"
>
<option :value="null" disabled>Wybierz wagon</option> <option :value="null" disabled>Wybierz wagon</option>
<option v-for="car in carOptions" :value="car" :key="car.type"> <option v-for="car in carOptions" :value="car" :key="car.type">
@@ -108,8 +118,16 @@ export default defineComponent({
this.isReadyStockListOpen = bool; this.isReadyStockListOpen = bool;
}, },
onVehicleSelect(type: 'loco' | 'car') {
this.$nextTick(() => {
if (!this.store.chosenLoco && !this.store.chosenCar) return;
this.store.chosenVehicle = type == 'loco' ? this.store.chosenLoco : this.store.chosenCar;
});
},
addVehicle() { addVehicle() {
const vehicle = this.store.chosenCar || this.store.chosenLoco; const vehicle = this.store.chosenVehicle;
if (!vehicle) return; if (!vehicle) return;
@@ -201,64 +219,6 @@ export default defineComponent({
margin-bottom: 1em; margin-bottom: 1em;
} }
&_radio {
button {
padding: 0.25em 0.55em;
margin-right: 0.5em;
border: 2px solid white;
color: white;
font-size: 1em;
}
button:focus {
color: $accentColor;
}
button.checked {
border-color: $accentColor;
color: $accentColor;
font-weight: bold;
}
}
&_checkbox {
margin: 1em 0;
padding: 0 1.5em;
button {
position: relative;
color: #999;
&::before {
content: '';
width: 1.5ch;
height: 1.5ch;
display: block;
position: absolute;
bottom: 0.2ch;
left: -1.5em;
background-color: #999;
}
&.checked {
color: white;
font-weight: bold;
&::before {
background-color: $accentColor;
}
}
&:focus {
outline: 1px solid $accentColor;
}
}
}
&_list { &_list {
margin: 0.5em 0; margin: 0.5em 0;
@@ -271,7 +231,7 @@ export default defineComponent({
&_list button { &_list button {
margin-left: 0.5em; margin-left: 0.5em;
font-size: 0.8em; font-weight: bold;
&:hover img { &:hover img {
border-color: $accentColor; border-color: $accentColor;
+10 -23
View File
@@ -1,11 +1,5 @@
<template> <template>
<div class="bottom"> <div class="bottom">
<div class="bg-dimmer" v-if="store.isRandomizerCardOpen"></div>
<train-image />
<section class="spacer"></section>
<section class="stock-list"> <section class="stock-list">
<div class="stock-list_buttons"> <div class="stock-list_buttons">
<button class="btn" @click="downloadStock">POBIERZ POCIĄG</button> <button class="btn" @click="downloadStock">POBIERZ POCIĄG</button>
@@ -121,10 +115,9 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { computed, ComputedRef, defineComponent, inject, provide, reactive, ref } from 'vue'; import { defineComponent } from 'vue';
import { IStore, ILocomotive, ICarWagon } from '../types';
import RandomizerCard from './RandomizerCard.vue'; import RandomizerCard from './RandomizerCard.vue';
import TrainImage from './TrainImage.vue'; import TrainImage from './TrainImageSection.vue';
import addIcon from '../assets/add-icon.svg'; import addIcon from '../assets/add-icon.svg';
import subIcon from '../assets/sub-icon.svg'; import subIcon from '../assets/sub-icon.svg';
@@ -154,12 +147,7 @@ export default defineComponent({
const attr = targetNode.attributes.getNamedItem('data-ignore-outside'); const attr = targetNode.attributes.getNamedItem('data-ignore-outside');
if ( if (!attr && targetNode.tagName.toLowerCase() != 'select' && targetNode.tagName.toLowerCase() != 'option')
!attr &&
!(this.$refs['list'] as Node).contains(targetNode) &&
targetNode.tagName.toLowerCase() != 'select' &&
targetNode.tagName.toLowerCase() != 'option'
)
this.store.chosenStockListIndex = -1; this.store.chosenStockListIndex = -1;
}); });
}, },
@@ -212,24 +200,23 @@ export default defineComponent({
this.store.chosenStockListIndex = vehicleID; this.store.chosenStockListIndex = vehicleID;
if ((this.store.chosenCar || this.store.chosenLoco)?.imageSrc != vehicle.imgSrc) this.store.imageLoading = true; if (this.store.chosenVehicle?.imageSrc != vehicle.imgSrc) this.store.imageLoading = true;
if (this.store.showSupporter && !vehicle.supportersOnly) { if (this.store.showSupporter && !vehicle.supportersOnly) {
this.store.showSupporter = false; this.store.showSupporter = false;
} }
if (vehicle.isLoco) { if (vehicle.isLoco) {
this.store.chosenLocoPower = vehicle.useType; const chosenLoco = this.store.locoDataList.find((v) => v.type == vehicle.type) || null;
this.store.chosenVehicle = chosenLoco;
this.store.chosenLoco = chosenLoco;
this.store.chosenLoco = this.store.locoDataList.find((v) => v.type == vehicle.type) || null;
this.store.chosenCar = null;
this.store.chosenCargo = null; this.store.chosenCargo = null;
} else { } else {
this.store.chosenCarUseType = vehicle.useType; const chosenCar = this.store.carDataList.find((v) => v.type == vehicle.type) || null;
this.store.chosenVehicle = chosenCar;
this.store.chosenCar = chosenCar;
this.store.chosenLoco = null;
this.store.chosenCar = this.store.carDataList.find((v) => v.type == vehicle.type) || null;
this.store.chosenCargo = vehicle.cargo || null; this.store.chosenCargo = vehicle.cargo || null;
} }
+2 -4
View File
@@ -114,8 +114,6 @@ export default defineComponent({
return list; return list;
}, [] as string[]), }, [] as string[]),
includeSupporterVehicles: inject('includeSupporterVehicles') as boolean,
}; };
}, },
@@ -204,7 +202,7 @@ export default defineComponent({
let locoSet = this.store.locoDataList let locoSet = this.store.locoDataList
.filter((loco) => loco.power == 'loco-e' || loco.power == 'loco-s') .filter((loco) => loco.power == 'loco-e' || loco.power == 'loco-s')
.filter((loco) => (!this.includeSupporterVehicles && loco.supportersOnly ? false : true)); .filter((loco) => (loco.supportersOnly ? false : true));
if (this.chosenCarTypes.some((car) => this.cargoTypes.includes(car))) if (this.chosenCarTypes.some((car) => this.cargoTypes.includes(car)))
locoSet = locoSet.filter((loco) => !loco.type.startsWith('EP')); locoSet = locoSet.filter((loco) => !loco.type.startsWith('EP'));
@@ -218,7 +216,7 @@ export default defineComponent({
totalStockMass += this.store.stockList[0].mass; totalStockMass += this.store.stockList[0].mass;
let availableCarsSet = this.store.carDataList.filter((cargoCar) => { let availableCarsSet = this.store.carDataList.filter((cargoCar) => {
if (!this.includeSupporterVehicles && cargoCar.supportersOnly) return false; if (cargoCar.supportersOnly) return false;
if (this.chosenCarTypes.find((carType) => cargoCar.type.includes(carType))) return true; if (this.chosenCarTypes.find((carType) => cargoCar.type.includes(carType))) return true;
+5 -5
View File
@@ -39,7 +39,7 @@
<script lang="ts"> <script lang="ts">
import { defineComponent, inject } from 'vue'; import { defineComponent, inject } from 'vue';
import { IStore, ILocomotive, ICarWagon } from '../types'; import { IStore, ILocomotive, ICarWagon, Vehicle } from '../types';
import iconEIC from '../assets/EIC.png'; import iconEIC from '../assets/EIC.png';
import iconIC from '../assets/IC.svg'; import iconIC from '../assets/IC.svg';
@@ -127,9 +127,9 @@ export default defineComponent({
this.store.chosenRealStockName = `${type} ${number} ${name}`; this.store.chosenRealStockName = `${type} ${number} ${name}`;
stockArray.forEach((type, i) => { stockArray.forEach((type, i) => {
let vehicle; let vehicle: Vehicle | null = null;
if (i == 0) vehicle = this.store.locoDataList.find((loco) => loco.type == stockArray[0]); if (i == 0) vehicle = this.store.locoDataList.find((loco) => loco.type == stockArray[0]) || null;
else vehicle = this.store.carDataList.find((car) => car.type == type); else vehicle = this.store.carDataList.find((car) => car.type == type) || null;
this.addVehicle(vehicle); this.addVehicle(vehicle);
}); });
@@ -137,7 +137,7 @@ export default defineComponent({
this.exit(); this.exit();
}, },
addVehicle(vehicle: ILocomotive | ICarWagon | undefined) { addVehicle(vehicle: Vehicle | null) {
if (!vehicle) return; if (!vehicle) return;
const stockObj = { const stockObj = {
@@ -1,55 +1,55 @@
<template> <template>
<div class="image"> <section class="train-image">
<div class="image__wrapper"> <div class="train-image__wrapper">
<div <div class="train-image__content">
class="image__content" <div class="no-img" v-if="!store.chosenVehicle">PODGLĄD WYBRANEGO POJAZDU</div>
:class="{
supporter: (store.chosenLoco || store.chosenCar)?.supportersOnly,
}"
>
<div class="no-img" v-if="!store.chosenCar && !store.chosenLoco">PODGLĄD WYBRANEGO POJAZDU</div>
<div class="empty-message" v-if="store.imageLoading">ŁADOWANIE OBRAZU...</div> <div class="empty-message" v-if="store.imageLoading">ŁADOWANIE OBRAZU...</div>
<img <img
v-if="store.chosenLoco || store.chosenCar" v-if="store.chosenVehicle"
:src="store.chosenLoco?.imageSrc || store.chosenCar?.imageSrc" :src="store.chosenVehicle.imageSrc"
:alt="store.chosenLoco?.type || store.chosenCar?.type" :alt="store.chosenVehicle.type"
@load="onImageLoad" @load="onImageLoad"
@click="onImageClick" @click="onImageClick"
/> />
</div> </div>
</div> </div>
<div class="image__info" v-if="store.chosenLoco || store.chosenCar"> <div class="image__info" v-if="store.chosenVehicle">
<b class="text--accent">{{ (store.chosenLoco || store.chosenCar)?.type }} </b> <b class="text--accent">{{ store.chosenVehicle.type }} </b>
<div style="color: #ccc"> <div style="color: #ccc">
<b>{{ vehicleTypes[store.chosenLoco?.power || store.chosenCar?.useType || 'loco-e'] }}</b> <b>{{
vehicleTypes[
isLocomotive(store.chosenVehicle) ? store.chosenVehicle.power : store.chosenVehicle.useType || 'loco-e'
]
}}</b>
<div> <div>
{{ (store.chosenCar || store.chosenLoco)?.length }}m | {{ (store.chosenCar || store.chosenLoco)?.mass }}t | {{ store.chosenVehicle.length }}m | {{ store.chosenVehicle.mass }}t | {{ store.chosenVehicle.maxSpeed }} km/h
{{ (store.chosenCar || store.chosenLoco)?.maxSpeed }} km/h
</div> </div>
<div v-if="store.chosenLoco">Typ kabiny: {{ store.chosenLoco.cabinType }}</div> <div v-if="isLocomotive(store.chosenVehicle)">Typ kabiny: {{ store.chosenVehicle.cabinType }}</div>
<div v-if="store.chosenCar"> <div v-else>
{{ {{
store.chosenCar.useType == 'car-cargo' store.chosenVehicle.useType == 'car-cargo'
? carUsage[store.chosenCar.constructionType] ? carUsage[store.chosenVehicle.constructionType]
: 'Typ konstrukcji: ' + store.chosenCar.constructionType : 'Typ konstrukcji: ' + store.chosenVehicle.constructionType
}} }}
</div> </div>
</div> </div>
</div> </div>
<div class="image__info" v-else>Wybierz pojazd lub wagon, aby zobaczyć jego podgląd powyżej</div> <div class="image__info" v-else>Wybierz pojazd lub wagon, aby zobaczyć jego podgląd powyżej</div>
</div> </section>
</template> </template>
<script lang="ts"> <script lang="ts">
import carUsage from '../data/carUsage.json'; import carUsage from '../data/carUsage.json';
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import { useStore } from '../store'; import { useStore } from '../store';
import { isLocomotive } from '../utils/vehicleUtils';
import { ILocomotive, Vehicle } from '../types';
export default defineComponent({ export default defineComponent({
setup() { setup() {
@@ -80,8 +80,12 @@ export default defineComponent({
this.store.imageLoading = false; this.store.imageLoading = false;
}, },
isLocomotive(vehicle: Vehicle): vehicle is ILocomotive {
return isLocomotive(vehicle);
},
onImageClick() { onImageClick() {
const chosenVehicle = this.store.chosenCar || this.store.chosenLoco; const chosenVehicle = this.store.chosenVehicle;
if (!chosenVehicle) return; if (!chosenVehicle) return;
@@ -92,15 +96,16 @@ export default defineComponent({
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.image { .train-image {
flex-grow: 2;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: flex-start;
margin-top: 2.5em;
} }
.image { .train-image {
&__wrapper { &__wrapper {
max-width: 380px; max-width: 380px;
width: 22em; width: 22em;
+3 -1
View File
@@ -1,7 +1,8 @@
import { IStore } from './types'; import { ICarWagon, ILocomotive, IStore } from './types';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { carDataList, isTrainPassenger, locoDataList, maxStockSpeed, totalLength, totalMass } from './utils/vehicleUtils'; import { carDataList, isTrainPassenger, locoDataList, maxStockSpeed, totalLength, totalMass } from './utils/vehicleUtils';
export const useStore = defineStore({ export const useStore = defineStore({
id: 'store', id: 'store',
state: () => state: () =>
@@ -9,6 +10,7 @@ export const useStore = defineStore({
chosenCar: null, chosenCar: null,
chosenLoco: null, chosenLoco: null,
chosenCargo: null, chosenCargo: null,
chosenVehicle: null,
showSupporter: false, showSupporter: false,
imageLoading: false, imageLoading: false,
-1
View File
@@ -24,7 +24,6 @@ html {
margin: 0; margin: 0;
padding: 0; padding: 0;
min-height: 100vh;
font-family: "Lato", sans-serif; font-family: "Lato", sans-serif;
background-color: $bgColor; background-color: $bgColor;
+5
View File
@@ -1,8 +1,12 @@
export type Vehicle = ILocomotive | ICarWagon;
export interface IStore { export interface IStore {
chosenCar: ICarWagon | null; chosenCar: ICarWagon | null;
chosenLoco: ILocomotive | null; chosenLoco: ILocomotive | null;
chosenCargo: ICargo | null; chosenCargo: ICargo | null;
chosenVehicle: Vehicle | null;
showSupporter: boolean; showSupporter: boolean;
imageLoading: boolean; imageLoading: boolean;
@@ -70,3 +74,4 @@ export interface IStock {
count: number; count: number;
imgSrc: string; imgSrc: string;
} }