From 7596b7ec2c77466c14d01de6b9ee3e876cb8fa6f Mon Sep 17 00:00:00 2001 From: Spythere Date: Sat, 8 Mar 2025 02:14:43 +0100 Subject: [PATCH] chore: improved stock actions layout; added stock bookmarking --- src/App.vue | 24 ++- src/components/tabs/StockListTab.vue | 73 +++++++-- src/components/tabs/StorageTab.vue | 226 ++++++++++++++++++--------- src/locales/en.json | 3 + src/locales/pl.json | 7 +- src/store.ts | 9 +- src/styles/_global.scss | 54 +++++-- 7 files changed, 283 insertions(+), 113 deletions(-) diff --git a/src/App.vue b/src/App.vue index 3a7d61a..53749eb 100644 --- a/src/App.vue +++ b/src/App.vue @@ -18,10 +18,30 @@ export default defineComponent({ return { store: useStore() }; }, - async created() { - this.store.handleRouting(); + created() { + this.loadStockDataFromStorage(); this.store.setupAPIData(); }, + + methods: { + loadStockDataFromStorage() { + const savedData = localStorage.getItem('savedStockData'); + + if (!savedData) { + localStorage.setItem('savedStockData', JSON.stringify({})); + return; + } + + try { + this.store.storageStockData = JSON.parse(savedData); + } catch (error) { + console.error( + 'Wystąpił błąd podczas przetwarzania danych o składach z localStorage!', + error + ); + } + }, + }, }); diff --git a/src/components/tabs/StockListTab.vue b/src/components/tabs/StockListTab.vue index 0a55094..ba98c3b 100644 --- a/src/components/tabs/StockListTab.vue +++ b/src/components/tabs/StockListTab.vue @@ -2,15 +2,21 @@
- - + +
@@ -244,10 +260,14 @@ import { ArrowPathIcon, ArrowUpTrayIcon, ArrowUturnLeftIcon, + BookmarkIcon, ChevronDownIcon, ChevronUpIcon, ClipboardDocumentIcon, + FolderPlusIcon, + ClipboardDocumentCheckIcon, TrashIcon, + DocumentDuplicateIcon, } from '@heroicons/vue/20/solid'; export default defineComponent({ @@ -255,13 +275,17 @@ export default defineComponent({ components: { StockThumbnails, Checkbox, + FolderPlusIcon, ArrowDownTrayIcon, ArrowPathIcon, ArrowUpTrayIcon, ArrowUturnLeftIcon, + BookmarkIcon, ChevronDownIcon, ChevronUpIcon, ClipboardDocumentIcon, + ClipboardDocumentCheckIcon, + DocumentDuplicateIcon, TrashIcon, }, @@ -289,7 +313,6 @@ export default defineComponent({ return this.store.realCompositionList.find((rc) => rc.stockString == currentStockString); }, - stockIsEmpty() { return this.store.stockList.length == 0; }, @@ -495,6 +518,30 @@ export default defineComponent({ inputEl.value = ''; }, + saveStockDataToStorage() { + if (this.store.stockList.length == 0) return; + + const defaultName = `${this.store.stockList[0].vehicleRef.type} ${(this.store.totalWeight / 1000).toFixed(1)}t; ${this.store.totalLength}m; vmax ${this.store.maxStockSpeed}`; + const entryName = prompt(this.$t('stocklist.prompt-bookmark'), defaultName); + + if (!entryName) return; + + if (entryName in this.store.storageStockData) { + const overwriteData = confirm(this.$t('stocklist.prompt-bookmark-overwrite')); + + if (!overwriteData) return; + } + + this.store.storageStockData[entryName] = this.store.stockString; + + try { + localStorage.setItem('savedStockData', JSON.stringify(this.store.storageStockData)); + this.store.chosenStorageStockName = entryName; + } catch (error) { + console.error('Wystąpił błąd podczas zapisywania składu do localStorage!', error); + } + }, + async uploadStockFromClipboard() { try { const content = await navigator.clipboard.readText(); @@ -588,7 +635,7 @@ export default defineComponent({ display: grid; gap: 0.5em; - grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + grid-template-columns: repeat(auto-fit, minmax(70px, 1fr)); button { width: 100%; diff --git a/src/components/tabs/StorageTab.vue b/src/components/tabs/StorageTab.vue index 3caab16..18d6d40 100644 --- a/src/components/tabs/StorageTab.vue +++ b/src/components/tabs/StorageTab.vue @@ -6,91 +6,106 @@
-
- - -
+
+ +
  • +
    + -
      -
    • -
    • -
    +
    + + + +
    +
    + +
    + {{ + stockString + .split(';') + .map((s) => s.split(/:|,/)[0]) + .join(' + ') + }} +
    +
  • +
    +
    - diff --git a/src/locales/en.json b/src/locales/en.json index 3dea2f3..edccd64 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -52,6 +52,8 @@ "alert-copied": "The rolling stock has been copied to your clipboard!", "alert-empty": "Lista pojazdów jest pusta!", "prompt-file": "Name a file and download it to the Presets folder (Documents/TTSK/TrainDriver2):", + "prompt-bookmark": "Enter the name of this composition:", + "prompt-bookmark-overwrite": "A composition with this name is already bookmarked! Do you want to overwrite it?", "vehicle-no": "VEHICLE NO.", "no-vehicle-chosen": "NO VEHICLE CHOSEN", "action-move-up": "MOVE UP", @@ -63,6 +65,7 @@ "action-copy": "COPY TO CLIPBOARD", "action-reset": "RESET", "action-shuffle": "SHUFFLE", + "action-bookmark": "BOOKMARK", "mass": "Mass", "mass-accepted": "accepted", "length": "Length", diff --git a/src/locales/pl.json b/src/locales/pl.json index 7c2b04b..e4c69b7 100644 --- a/src/locales/pl.json +++ b/src/locales/pl.json @@ -53,17 +53,20 @@ "alert-copied": "Skład został skopiowany do twojego schowka!", "alert-empty": "Lista pojazdów jest pusta!", "prompt-file": "Nazwij plik, a następnie pobierz do folderu Presets (Dokumenty/TTSK/TrainDriver2):", + "prompt-bookmark": "Nazwij skład do zapisania:", + "prompt-bookmark-overwrite": "Skład o tej nazwie jest już zapisany. Czy chcesz go podmienić?", "vehicle-no": "POJAZD NR", "no-vehicle-chosen": "NIE WYBRANO POJAZDU", "action-move-up": "PRZENIEŚ WYŻEJ", "action-move-down": "PRZENIEŚ NIŻEJ", "action-remove": "USUŃ", - "action-upload-file": "WCZYTAJ (PLIK)", - "action-upload-clipboard": "WCZYTAJ (SCHOWEK)", + "action-upload-file": "WCZYTAJ Z PLIKU", + "action-upload-clipboard": "WCZYTAJ ZE SCHOWKA", "action-download": "POBIERZ DO PLIKU", "action-copy": "SKOPIUJ DO SCHOWKA", "action-reset": "ZRESETUJ", "action-shuffle": "PRZETASUJ", + "action-bookmark": "ZAPISZ", "mass": "Masa", "mass-accepted": "dopuszczalna", "length": "Długość", diff --git a/src/store.ts b/src/store.ts index 3d8526d..d81fd9a 100644 --- a/src/store.ts +++ b/src/store.ts @@ -61,6 +61,9 @@ export const useStore = defineStore({ lastFocusedElement: null as HTMLElement | null, + storageStockData: {} as Record, + chosenStorageStockName: '', + compatibleSimulatorVersion: '2024.3.1', }), @@ -137,11 +140,5 @@ export const useStore = defineStore({ async setupAPIData() { await this.fetchVehiclesAPI(); }, - - handleRouting() { - if (window.location.search.includes('trainId=')) { - const trainId = window.location.search; - } - }, }, }); diff --git a/src/styles/_global.scss b/src/styles/_global.scss index 5935371..2fd9616 100644 --- a/src/styles/_global.scss +++ b/src/styles/_global.scss @@ -122,21 +122,43 @@ button { } } -[data-tooltip]:hover::after, -[data-tooltip]:focus::after { - position: absolute; - transform: translateX(10px); - - content: attr(data-tooltip); - color: white; - background: black; - padding: 0.5em; - max-width: 300px; - z-index: 100; -} - [data-tooltip] { cursor: pointer; + + &:hover::after, + &:focus-visible::after { + position: absolute; + transform: translateX(10px); + + content: attr(data-tooltip); + color: white; + background: black; + padding: 0.5em; + max-width: 300px; + z-index: 100; + } +} + +[data-button-tooltip] { + position: relative; + + &:hover::after, + &:focus-visible::after { + position: absolute; + + width: 100%; + max-width: 300px; + + top: 100%; + transform: translateY(5px); + border-radius: inherit; + + content: attr(data-button-tooltip); + color: white; + background: #111; + padding: 0.5em; + z-index: 100; + } } .btn, @@ -190,7 +212,8 @@ button { align-items: center; gap: 0.5em; - img, svg { + img, + svg { width: 20px; height: 20px; } @@ -200,7 +223,8 @@ button { font-weight: bold; transition: all 250ms; background: none; - padding: 0; + padding: 0.25em; + border-radius: 0; &:focus-visible { outline: 1px solid white;