36 Commits

Author SHA1 Message Date
Spythere 794eb97b3b Merge pull request #23 from Spythere/development
Site migration to a new domain
2026-03-08 01:38:09 +01:00
Spythere 4fce109332 chore: added info bar about migration to a new domain 2026-03-07 19:22:40 +01:00
Spythere 9e4c69e87d Merge pull request #22 from Spythere/development
v1.7.0
2026-01-30 22:28:14 +01:00
Spythere 7e789b0d9f chore(index): added OpenGraph banner image metadata 2026-01-30 21:02:32 +01:00
Spythere 19ed3d6a1c chore(options): changed default autofill values from false to true 2026-01-30 20:44:29 +01:00
Spythere bfd14a8471 chore(message): increased message box base height; fixed vertical overflow 2026-01-23 17:43:10 +01:00
Spythere 039c52a8b7 chore: updating color scheme with dark mode 2026-01-23 17:40:33 +01:00
Spythere b373cbcba1 feat: setting preferred theme based on browser media 2026-01-23 13:48:53 +01:00
Spythere 7858088db0 chore(locales): updated en locale 2026-01-23 13:44:10 +01:00
Spythere 1c93684218 feat: resetting order body 2026-01-23 13:42:22 +01:00
Spythere 1a969731cd fix(app): responsiveness issues 2026-01-22 00:44:10 +01:00
Spythere d408f0a706 chore(packages): upgrade 2026-01-22 00:28:14 +01:00
Spythere c97806c920 chore(app): added prefetching images & fonts; optimized assets 2026-01-22 00:26:47 +01:00
Spythere b1e3346b59 bump(version): 1.7.0 2026-01-15 19:55:22 +01:00
Spythere 1f8365340b refactor: organized files, refreshed design and layout 2026-01-15 19:55:02 +01:00
Spythere 4d06b85fc1 chore(workflows): added deploying files to VPS 2025-12-15 13:33:36 +01:00
Spythere d5d0551c17 Merge pull request #20 from Spythere/development
Hotfix for 1.6.0
2025-07-11 02:31:13 +02:00
Spythere 35a883d608 chore: code cleanup 2025-07-11 02:30:06 +02:00
Spythere 2efa4a4f9a hotfix: checkpoint abbreviation 2025-07-11 02:29:41 +02:00
Spythere 2c5eb27484 Merge pull request #19 from Spythere/development
hotfix: filling station name instead of dispatcher name
2025-07-07 22:59:54 +02:00
Spythere 92586fb880 hotfix(train picker): filling station name instead of dispatcher name 2025-07-07 22:59:19 +02:00
Spythere e0e0504366 Merge pull request #18 from Spythere/development
v1.6.0
2025-07-07 19:04:13 +02:00
Spythere 3c9cdac832 chore: added github releases webhook 2025-07-07 18:57:33 +02:00
Spythere 4162f5e137 chore: added github releases webhook 2025-07-07 18:56:31 +02:00
Spythere b2b5716cc6 fix: footer typo 2025-07-07 18:38:05 +02:00
Spythere 26b0556bfa fix: translations 2025-07-07 18:34:15 +02:00
Spythere d59152fccd chore: nav buttons transition 2025-07-07 18:31:40 +02:00
Spythere 864967a77a fix: order "O" rows generation 2025-07-07 18:23:15 +02:00
Spythere 37c2650841 chore: changed lang button layout 2025-07-07 18:15:39 +02:00
Spythere 5b9b86248f chore: added changelog for update modal 2025-07-07 18:00:07 +02:00
Spythere 43b0dc9fa0 chore: packages upgrade 2025-07-01 18:25:11 +02:00
Spythere 972c73281d bump: v1.6.0 2025-07-01 18:24:16 +02:00
Spythere 8538072a60 refactor: added translations 2025-07-01 18:24:04 +02:00
Spythere e298a17ab7 chore: added loading locale from browser data 2025-07-01 16:20:25 +02:00
Spythere 519665697b chore: added i18n 2025-07-01 16:15:50 +02:00
Spythere c5221e337b chore: added multiline support 2025-07-01 16:12:53 +02:00
45 changed files with 1531 additions and 499 deletions
+1
View File
@@ -2,3 +2,4 @@ VITE_APP_API_URL=https://stacjownik.spythere.eu/api
VITE_APP_SWDR_URL=https://api.td2.info.pl
VITE_APP_ORDER_VERSION=2
#VITE_UPDATE_TEST='test'
+1 -1
View File
@@ -5,7 +5,7 @@ name: Deploy to Firebase Hosting on merge
'on':
push:
branches:
- main
- main-old
jobs:
build_and_deploy:
runs-on: ubuntu-latest
@@ -0,0 +1,17 @@
on:
release:
types: [published]
jobs:
github-releases-to-discord:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Github Releases To Discord
uses: SethCohen/github-releases-to-discord@v1.13.1
with:
webhook_url: '${{ secrets.WEBHOOK_URL }}'
color: '9936031'
footer_title: 'Changelog - GeneraTOR'
footer_timestamp: true
+23
View File
@@ -0,0 +1,23 @@
name: Build & Deploy to VPS
on:
push:
branches:
- main
env:
PROJECT_NAME: generator-td2
jobs:
build_and_deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build the app
run: yarn && yarn build
- name: Setup SSH key for connection with the server
run: |
mkdir -p ~/.ssh
echo "${{ secrets.VPS_SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa && chmod 600 ~/.ssh/id_rsa
- name: Send new files
run: rsync -avP -e "ssh -o StrictHostKeyChecking=no -i ~/.ssh/id_rsa -p 2022" ./dist/ ${{ secrets.VPS_USER }}@${{ secrets.VPS_HOST }}:/var/www/$PROJECT_NAME --delete
+64 -2
View File
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="pl">
<head>
<meta charset="utf-8" />
@@ -24,9 +24,71 @@
<meta name="msapplication-TileImage" content="/ms-icon-144x144.png" />
<meta name="theme-color" content="#ffffff" />
<!-- Preloads -->
<link
rel="preload"
href="/fonts/libre-franklin-500.woff2"
as="font"
type="font/woff2"
crossorigin
/>
<link
rel="preload"
href="/fonts/libre-franklin-700.woff2"
as="font"
type="font/woff2"
crossorigin
/>
<link
rel="preload"
href="/fonts/libre-franklin-800.woff2"
as="font"
type="font/woff2"
crossorigin
/>
<link
rel="preload"
href="/fonts/libre-franklin-regular.woff2"
as="font"
type="font/woff2"
crossorigin
/>
<link rel="preload" href="/favicon.ico" as="image" />
<title>GeneraTOR</title>
<meta name="description" content="Generator rozkazów pisemnych online" />
<meta name="description" content="Generator rozkazów pisemnych dla symulatora Train Driver 2" />
<!-- Static OpenGraph meta -->
<meta property="og:url" content="https://generator-td2.web.app/" />
<meta property="og:type" content="website" />
<meta property="og:title" content="GeneraTOR" />
<meta
property="og:description"
content="Generator rozkazów pisemnych dla symulatora Train Driver 2"
/>
<meta
property="og:image"
content="https://raw.githubusercontent.com/Spythere/api/refs/heads/main/thumbnails/generator-banner.png"
/>
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:site_name" content="GeneraTOR" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="GeneraTOR" />
<meta
name="twitter:description"
content="Generator rozkazów pisemnych dla symulatora Train Driver 2"
/>
<meta
name="twitter:image"
content="https://raw.githubusercontent.com/Spythere/api/refs/heads/main/thumbnails/generator-banner.png"
/>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
+5 -2
View File
@@ -1,6 +1,6 @@
{
"name": "genera-tor",
"version": "1.5.2",
"version": "1.7.0",
"private": true,
"type": "module",
"scripts": {
@@ -13,14 +13,17 @@
},
"dependencies": {
"axios": "^1.6.2",
"lucide-vue-next": "^0.562.0",
"pinia": "^2.1.7",
"showdown": "^2.1.0",
"vue": "^3.3.11",
"vue-i18n": "9.8.0",
"vue-i18n": "11",
"vue-router": "^4.2.5",
"vue-tsc": "^2.2.8"
},
"devDependencies": {
"@types/node": "^22.13.10",
"@types/showdown": "^2.0.6",
"@vitejs/plugin-vue": "^4.5.2",
"@vue/eslint-config-prettier": "^8.0.0",
"@vue/eslint-config-typescript": "^12.0.0",
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+123 -43
View File
@@ -1,50 +1,152 @@
<template>
<div id="app_wrapper">
<router-view />
<transition name="slide-anim">
<div v-if="needRefresh" class="update-prompt" @click="updateServiceWorker(true)">
Nowa wersja GeneraTORa dostępna!
<u>Kliknij, aby odświeżyć aplikację!</u>
</div>
<UpdateCard />
</transition>
<footer>
&copy; <a href="https://td2.info.pl/profile/?u=20777">Spythere</a>
{{ new Date().getUTCFullYear() }} | v.{{ appVersion }}
</footer>
<transition name="slide-anim">
<UpdatePrompt />
</transition>
<transition name="slide-anim">
<MigrationInfo v-if="store.isMigrationInfoOpen" />
</transition>
<div class="app-body">
<Navbar />
<main>
<RouterView />
</main>
</div>
</div>
</template>
<script lang="ts">
import { useRegisterSW } from 'virtual:pwa-register/vue';
import { defineComponent } from 'vue';
import packageInfo from '../package.json';
import { useStore } from './store/store';
import UpdateCard from './components/Global/UpdateCard.vue';
import orderStorageMixin from './mixins/orderStorageMixin';
import { useStore } from './store/store';
import packageInfo from '../package.json';
import axios from 'axios';
import StorageManager from './managers/storageManager';
import Navbar from './components/App/Navbar.vue';
import UpdatePrompt from './components/Global/UpdatePrompt.vue';
import MigrationInfo from './components/Global/MigrationInfo.vue';
const STORAGE_VERSION_KEY = 'app_version';
export default defineComponent({
components: { UpdateCard, UpdatePrompt, Navbar, MigrationInfo },
mixins: [orderStorageMixin],
setup() {
const { offlineReady, needRefresh, updateServiceWorker } = useRegisterSW({ immediate: true });
return { offlineReady, needRefresh, updateServiceWorker };
},
data() {
return { appVersion: packageInfo.version, store: useStore() };
},
created() {
document.title = `GeneraTOR ${this.appVersion}`;
this.store.orderDarkMode = this.getOrderSetting('dark-mode') === 'true';
this.init();
},
methods: {
init() {
this.loadLang();
this.setupDarkMode();
this.loadSettings();
this.handleMigrationInfo();
this.checkAppVersion();
this.handleQueries();
},
loadSettings() {
document.title = `GeneraTOR ${this.appVersion}`;
},
setupDarkMode() {
if (this.getOrderSetting('dark-mode') === null) {
const prefersDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
this.saveOrderSetting('dark-mode', prefersDarkMode);
}
this.store.orderDarkMode = this.getOrderSetting('dark-mode') === 'true';
document.documentElement.setAttribute(
'data-theme',
this.store.orderDarkMode ? 'dark' : 'light'
);
},
handleQueries() {
const query = new URLSearchParams(window.location.search);
const id = query.get('sceneryId');
if (id != null) {
this.store.orderMode = 'OrderTrainPicker';
this.store.panelMode = 'OrderTrainPickerPanel';
}
},
async checkAppVersion() {
const storageVersion = StorageManager.getStringValue(STORAGE_VERSION_KEY);
try {
const releaseData = await (
await axios.get('https://api.github.com/repos/Spythere/genera-tor/releases/latest')
).data;
if (!releaseData) return;
this.store.appUpdateData.version = this.appVersion;
this.store.appUpdateData.changelog = releaseData.body;
this.store.appUpdateData.releaseURL = releaseData.html_url;
this.store.updateCardOpen =
(storageVersion != '' && storageVersion != this.appVersion) ||
import.meta.env.VITE_UPDATE_TEST === 'test';
} catch (error) {
console.error(`Wystąpił błąd podczas pobierania danych z API GitHuba: ${error}`);
}
StorageManager.setStringValue(STORAGE_VERSION_KEY, this.appVersion);
},
changeLang(lang: string) {
this.$i18n.locale = lang;
this.store.currentAppLocale = lang;
StorageManager.setStringValue('lang', lang);
},
loadLang() {
const storageLang = StorageManager.getStringValue('lang');
if (storageLang) {
this.changeLang(storageLang);
return;
}
if (!window.navigator.language) return;
const naviLanguage = window.navigator.language.toString();
if (!naviLanguage.startsWith('pl')) {
this.changeLang('en');
}
},
handleMigrationInfo() {
// Show only on old domain
if (location.hostname !== 'generator-td2.web.app' && location.hostname != 'localhost') return;
const showInfo = localStorage.getItem('showMigrationInfo');
// Do not show if already acknowledged
if (showInfo === 'false') return;
setTimeout(() => {
this.store.isMigrationInfoOpen = true;
}, 2000);
}
}
});
@@ -56,31 +158,9 @@ export default defineComponent({
#app {
color: white;
min-height: 100vh;
}
.update-prompt {
position: fixed;
bottom: 0;
left: 0;
padding: 0.5em;
font-weight: bold;
text-align: center;
width: 100%;
background-color: colors.$accentCol;
cursor: pointer;
}
footer {
text-align: center;
padding: 0.5em 0;
}
@media screen and (max-width: 500px) {
#app {
font-size: calc(1vw + 0.65rem);
+85
View File
@@ -0,0 +1,85 @@
<template>
<nav class="app-navbar">
<div class="navbar-brand">
<img src="/favicon.ico" alt="generator logo" width="30" />
<div>
<b>
Genera<span class="text--accent">TOR</span>
<sup class="text--grayed">v{{ version }}</sup>
</b>
<b class="brand-author">&nbsp;by Spythere</b>
</div>
</div>
<div class="navbar-actions">
<button class="g-button action icon" @click="switchDarkMode">
<LucideMoon :size="20" v-if="store.orderDarkMode" />
<LucideSun :size="20" v-else />
</button>
<button class="g-button action icon" @click="switchLang">
<LucideGlobe :size="20" />
<span>{{ store.currentAppLocale == 'pl' ? 'POL' : 'ENG' }}</span>
</button>
</div>
</nav>
</template>
<script setup lang="ts">
import { LucideGlobe, LucideMoon, LucideSun } from 'lucide-vue-next';
import { version } from '../../../package.json';
import { useStore } from '../../store/store';
const store = useStore();
function switchDarkMode() {
store.orderDarkMode = !store.orderDarkMode;
window.localStorage.setItem('dark-mode', `${store.orderDarkMode}`);
document.documentElement.setAttribute('data-theme', store.orderDarkMode ? 'dark' : 'light');
}
function switchLang() {
store.changeLang(store.currentAppLocale == 'pl' ? 'en' : 'pl');
}
</script>
<style lang="scss" scoped>
.app-navbar {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
height: 40px;
padding: 0.25em;
background-color: #1c1c1c;
}
.navbar-brand {
display: flex;
align-items: center;
gap: 0.5em;
sup {
font-size: 0.75em;
}
}
.brand-author {
font-size: 0.8em;
color: #aaa;
}
.navbar-actions {
display: flex;
align-items: center;
gap: 0.5em;
button {
padding: 0.5em;
gap: 0.25em;
border-radius: 0.5em;
}
}
</style>
+67
View File
@@ -0,0 +1,67 @@
<template>
<div class="migrate-info">
<div class="info-content">
<i18n-t keypath="migrate-info.line-1" for="migrate-info" tag="div">
<a href="https://generator-td2.spythere.eu/" target="_blank">{{
t('migrate-info.link')
}}</a>
</i18n-t>
<button class="g-button action accept-btn" @click="onAcceptButtonClick">
{{ t('migrate-info.accept-btn') }}
</button>
</div>
</div>
</template>
<script setup lang="ts">
import { useI18n } from 'vue-i18n';
import { useStore } from '../../store/store';
const store = useStore();
const { t } = useI18n();
function onAcceptButtonClick() {
store.isMigrationInfoOpen = false;
localStorage.setItem('showMigrationInfo', 'false');
}
</script>
<style lang="scss" scoped>
@use '../../styles/colors';
.migrate-info {
position: fixed;
z-index: 100;
bottom: 0;
left: 0;
padding: 0.25em;
text-align: center;
width: 100%;
background-color: colors.$warnCol;
color: black;
font-weight: bold;
}
.info-content {
display: flex;
justify-content: center;
align-items: center;
flex-wrap: wrap;
gap: 0.5em;
}
a {
color: black;
text-decoration: underline;
&:hover {
color: black;
}
}
.accept-btn {
color: white;
}
</style>
@@ -29,18 +29,17 @@
<script lang="ts">
import { defineComponent } from 'vue';
import { useStore } from '../store/store';
import orderHelperData from '../data/orderHelperData.json';
import { useStore } from '../../store/store';
export default defineComponent({
setup() {
return { store: useStore(), orderHelperData };
return { store: useStore() };
}
});
</script>
<style lang="scss" scoped>
@use '../styles/colors';
@use '../../styles/colors';
.content {
width: 100%;
+143
View File
@@ -0,0 +1,143 @@
<template>
<div class="update-card" v-if="store.updateCardOpen" @toggle-card="toggleCard(false)">
<div class="card-background"></div>
<div class="card-content">
<h1 style="margin-bottom: 0.5em">🚀 {{ $t('update.title') }}</h1>
<div class="changelog" v-if="htmlChangelog != ''" v-html="htmlChangelog"></div>
<div class="no-features" v-else>{{ $t('update.no-data') }}</div>
<button class="g-button action btn-confirm" ref="confirmButtonEl" @click="toggleCard(false)">
{{ $t('update.confirm') }}
</button>
<p class="bottom-info">
{{ $t('update.info-1') }}
<br />
<span v-html="$t('update.info-2')"></span>
</p>
</div>
</div>
</template>
<script lang="ts" setup>
import { computed, ref, watch } from 'vue';
import { Converter } from 'showdown';
import { useStore } from '../../store/store';
const converter = new Converter();
const store = useStore();
const confirmButtonEl = ref<HTMLButtonElement | null>(null);
watch(
computed(() => store.updateCardOpen),
(val) => {
if (val) {
confirmButtonEl.value?.focus();
}
}
);
const htmlChangelog = computed(() => {
if (store.appUpdateData.changelog == '') return '';
return converter.makeHtml(store.appUpdateData.changelog);
});
function toggleCard(value: boolean) {
store.updateCardOpen = value;
}
</script>
<style lang="scss" scoped>
// Converter styles
::v-deep(h1) {
text-align: center;
color: var(--clr-primary);
}
::v-deep(h2) {
padding: 0.25em 0;
border-bottom: 1px solid #aaa;
}
::v-deep(ul) {
list-style: disc;
padding: 1em;
line-height: 1.5em;
text-align: justify;
}
.update-card {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 200;
display: flex;
justify-content: center;
align-items: center;
}
.card-background {
position: absolute;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: 250;
cursor: pointer;
background-color: rgba(0, 0, 0, 0.55);
}
.card-content {
display: grid;
grid-template-rows: auto 1fr auto;
gap: 0.5em;
margin: 1em;
max-height: 95vh;
max-height: 95dvh;
background-color: #1a1a1a;
box-shadow: 0 0 15px 10px #0e0e0e;
border-radius: 1em;
overflow: auto;
padding: 1em;
min-height: 700px;
overflow: auto;
max-width: 700px;
z-index: 300;
}
.no-features {
text-align: center;
}
.changelog {
text-align: left;
}
button.btn-confirm {
padding: 0.5em 0.75em;
font-size: 1.1em;
}
p.bottom-info {
text-align: center;
color: #ccc;
}
a {
text-decoration: underline;
}
</style>
+34
View File
@@ -0,0 +1,34 @@
<template>
<div v-if="needRefresh" class="update-prompt" @click="updateServiceWorker(true)">
{{ $t('update.update-available-text') }}
<u>{{ $t('update.update-available-underline') }}</u>
</div>
</template>
<script setup lang="ts">
import { useRegisterSW } from 'virtual:pwa-register/vue';
const { needRefresh, updateServiceWorker } = useRegisterSW({ immediate: true });
</script>
<style lang="scss" scoped>
@use '../../styles/colors';
.update-prompt {
position: fixed;
bottom: 0;
left: 0;
padding: 0.5em;
z-index: 200;
font-weight: bold;
text-align: center;
width: 100%;
background-color: colors.$accentCol;
cursor: pointer;
}
</style>
@@ -1,4 +1,7 @@
<template>
<div class="order-container">
<OrderSideBar />
<div class="order" :class="{ dark: store.orderDarkMode }">
<div class="order_content">
<transition name="order-anim" mode="out-in">
@@ -9,20 +12,22 @@
<OrderFooter />
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { useStore } from '../store/store';
import OrderNVue from './OrderN.vue';
import OrderSVue from './OrderS.vue';
import { useStore } from '../../store/store';
import OrderN from './OrderN.vue';
import OrderS from './OrderS.vue';
import OrderO from './OrderO.vue';
import OrderFooter from './OrderFooter.vue';
import OrderOVue from './OrderO.vue';
import OrderSideBar from './OrderSideBar.vue';
const orderComponents = { orderN: OrderNVue, orderS: OrderSVue, orderO: OrderOVue };
const orderComponents = { orderN: OrderN, orderS: OrderS, orderO: OrderO };
export default defineComponent({
components: { OrderNVue, OrderSVue, OrderFooter },
components: { OrderN, OrderO, OrderS, OrderFooter, OrderSideBar },
setup() {
const store = useStore();
@@ -39,22 +44,32 @@ export default defineComponent({
</script>
<style lang="scss">
@use '../styles/colors';
@use '../../styles/colors';
$darkModeTextCol: #eee;
.order-container {
display: flex;
align-items: start;
max-width: 800px;
@media screen and (max-width: 1150px) {
flex-direction: column;
}
}
.order {
background-color: white;
color: black;
max-height: calc(100vh - 5em);
overflow: auto;
&.dark {
background-color: colors.$bgColDarker;
color: $darkModeTextCol;
}
max-height: 95vh;
overflow: auto;
font-size: 15px;
h2 {
@@ -52,8 +52,8 @@
<script lang="ts">
import { defineComponent } from 'vue';
import orderFooterMixin from '../mixins/orderFooterMixin';
import { useStore } from '../store/store';
import orderFooterMixin from '../../mixins/orderFooterMixin';
import { useStore } from '../../store/store';
export default defineComponent({
mixins: [orderFooterMixin],
@@ -334,8 +334,8 @@
<script lang="ts">
import { defineComponent, reactive } from 'vue';
import { useStore } from '../store/store';
import { handleOrderPlaceholders } from '../handlers/orderPlaceholderHandler';
import { handleOrderPlaceholders } from '../../handlers/orderPlaceholderHandler';
import { useStore } from '../../store/store';
type TOrderRows = 1 | 2 | 3 | 4 | 5;
@@ -350,7 +350,7 @@ export default defineComponent({
() => {
const { header } = order;
const message = `<i>Rozkaz pisemny "N" nr ${header.orderNo || '_'} dla pociągu nr ${
const message = `\n<i><b>Rozkaz pisemny "N" nr ${header.orderNo || '_'}</b> dla pociągu nr ${
header.trainNo || '_'
} dnia ${header.date}</i>`;
@@ -508,7 +508,7 @@ export default defineComponent({
for (let i = 0; i < this.order.rows.length; i++) {
if (!this.order.rows[i].enabled) continue;
message += ` <b> [ ${i + 1} ] </b> ${this.rowMethods[i + 1]()}`;
message += `\n--------\n<b>[ ${i + 1} ]</b> ${this.rowMethods[i + 1]()}`;
}
this.store.orderMessage = message;
@@ -77,7 +77,7 @@
<script lang="ts">
import { defineComponent, reactive } from 'vue';
import { useStore } from '../store/store';
import { useStore } from '../../store/store';
export default defineComponent({
name: 'OrderO',
@@ -90,7 +90,7 @@ export default defineComponent({
() => {
const { header } = order;
return `<i>Rozkaz pisemny "O" nr ${header.orderNo || '_'} dla pociągu nr ${
return `\n<i><b>Rozkaz pisemny "O" nr ${header.orderNo || '_'}</b> dla pociągu nr ${
header.trainNo || '_'
} dnia ${header.date || '_'}</i>`;
}
@@ -120,28 +120,25 @@ export default defineComponent({
generateMessage() {
let message = this.rowMethods[0]();
if (this.order.orderList.some((row) => row.name)) message += `<b> [ 1 ] </b>`;
const rowsMessageList = [];
if (this.order.orderList.some((row) => row.name)) {
message += `\n--------\n<b>[ 1 ]</b>`;
message += '\n1) zmniejszyć prędkość jazdy i zachować ostrożność';
message += '\n2) jechać ostrożnie (j.o.)\n';
}
for (let i = 0; i < this.order.orderList.length; i++) {
const row = this.order.orderList[i];
if (!row.name) continue;
let rowMessage = '';
rowMessage += ` ${row.name || '_'} od ${row.from || '_'} do ${row.to || '_'} kilometra`;
message += `\n- ${row.name || '_'} od ${row.from || '_'} do ${row.to || '_'} kilometra`;
if (row.vmax) rowMessage += ` prędkość najwyżej ${row.vmax} km/h`;
if (row.jo) rowMessage += ` jechać ostrożnie`;
if (row.vmax) message += ` prędkość najwyżej ${row.vmax} km/h`;
if (row.jo) message += ` jechać ostrożnie`;
rowMessage += ` z powodu: ${row.reason || '_'}`;
rowsMessageList.push(rowMessage);
message += ` z powodu: ${row.reason || '_'}`;
}
message += rowsMessageList.join('; ');
if (this.order.other) message += ` <b> [ 2 ] </b> Inne: ${this.order.other}`;
if (this.order.other) message += `\n--------\n<b>[ 2 ]</b> Inne: ${this.order.other}`;
this.store.orderMessage = message;
}
@@ -60,7 +60,9 @@
holder="nazwa sem."
:radio-checked="order.rows[0].radio1 == 'radio-1a-1'"
/>
<span v-if="order.rows[0].optionSignal == 'drogowskazowego'"> (odnoszącego się do wyjazdu pociągu)</span>
<span v-if="order.rows[0].optionSignal == 'drogowskazowego'">
(odnoszącego się do wyjazdu pociągu)</span
>
<br />
</label>
<hr />
@@ -284,8 +286,8 @@
<script lang="ts">
import { defineComponent, reactive } from 'vue';
import { handleOrderPlaceholders } from '../handlers/orderPlaceholderHandler';
import { useStore } from '../store/store';
import { handleOrderPlaceholders } from '../../handlers/orderPlaceholderHandler';
import { useStore } from '../../store/store';
type TOrderRows = 1 | 2 | 3 | 4;
@@ -300,7 +302,7 @@ export default defineComponent({
() => {
const { header } = order;
return `<i>Rozkaz pisemny "S" nr ${header.orderNo || '_'} dla ${header.for || '_'} nr ${
return `\n<i><b>Rozkaz pisemny "S" nr ${header.orderNo || '_'}</b> dla ${header.for || '_'} nr ${
header.trainNo || '_'
} dnia ${header.date || '_'}</i>`;
},
@@ -429,7 +431,7 @@ export default defineComponent({
for (let i = 0; i < 4; i++) {
if (!this.order.rows[i].enabled) continue;
message += ` <b> [ ${i + 1} ] </b> ${this.rowMethods[i + 1]()}`;
message += `\n--------\n<b>[ ${i + 1} ]</b> ${this.rowMethods[i + 1]()}`;
}
this.store.orderMessage = message;
@@ -23,7 +23,7 @@
<script lang="ts">
import { defineComponent } from 'vue';
import { useStore } from '../store/store';
import { useStore } from '../../store/store';
export default defineComponent({
data() {
@@ -61,11 +61,11 @@ export default defineComponent({
</script>
<style lang="scss" scoped>
@use '../styles/colors';
@use '../../styles/colors';
.sidebar_content {
display: grid;
grid-template-rows: repeat(3, 1fr);
display: flex;
flex-direction: column;
gap: 0.25em;
font-size: 1.5em;
@@ -126,10 +126,9 @@ button.option-save {
}
}
@media screen and (max-width: 650px) {
@media screen and (max-width: 1150px) {
.sidebar_content {
display: flex;
justify-content: space-between;
flex-direction: row;
& > button {
height: 40px;
@@ -1,10 +1,10 @@
<template>
<section class="order-list">
<h3>Zapisane rozkazy pisemne ({{ localOrderList.length }})</h3>
<h3>{{ $t('order-list.title') }} ({{ localOrderList.length }})</h3>
<transition-group name="list" tag="ul">
<li class="no-orders-warning" v-if="sortedOrderList.length == 0" :key="-1">
Brak zapisanych rozkazów!
{{ $t('order-list.no-saved-orders') }}
</li>
<li
@@ -14,8 +14,13 @@
>
<b class="text--accent">#{{ order.id.split('-')[1] }}&nbsp;</b>
<b>
{{ getOrderName(order.orderType) }} nr {{ order.orderBody['header']['orderNo'] }} dla
pociągu nr {{ order.orderBody['header']['trainNo'] }}
{{
$t('order-list.order-title', {
orderName: getOrderName(order.orderType),
orderNo: order.orderBody['header']['orderNo'],
trainNo: order.orderBody['header']['trainNo']
})
}}
</b>
<span
v-if="!order.orderVersion || order.orderVersion != ORDER_VERSION"
@@ -25,14 +30,18 @@
>&#9888;
</span>
<br />
{{ order.createdAt ? 'Dodano: ' : 'Zaktualizowano: ' }}
{{ $t(`order-list.order-${order.createdAt ? 'added' : 'updated'}`) }}
{{ new Date(order.createdAt || order.updatedAt || 0).toLocaleString('pl-PL') }}
<hr />
<div class="buttons">
<button class="g-button" @click="selectLocalOrder(order)">Wybierz</button>
<button class="g-button" @click="removeOrder(order)">Usuń</button>
<button class="g-button" @click="selectLocalOrder(order)">
{{ $t('order-list.button-order-select') }}
</button>
<button class="g-button" @click="removeOrder(order)">
{{ $t('order-list.button-order-remove') }}
</button>
</div>
</li>
</transition-group>
@@ -41,9 +50,9 @@
<script lang="ts">
import { defineComponent } from 'vue';
import orderStorageMixin from '../mixins/orderStorageMixin';
import { useStore } from '../store/store';
import { LocalStorageOrder } from '../types/orderTypes';
import orderStorageMixin from '../../mixins/orderStorageMixin';
import { useStore } from '../../store/store';
import { LocalStorageOrder } from '../../types/orderTypes';
export default defineComponent({
name: 'OrderList',
@@ -65,7 +74,7 @@ export default defineComponent({
methods: {
getOrderName(orderType: string) {
return `Rozkaz "${orderType.split('order')[1]}"`;
return orderType.split('order')[1];
},
removeOrder(order: LocalStorageOrder) {
@@ -105,7 +114,7 @@ export default defineComponent({
</script>
<style lang="scss" scoped>
@use '../styles/colors';
@use '../../styles/colors';
.list {
&-move,
@@ -1,40 +1,42 @@
<template>
<section class="order-message">
<h3>Wiadomość do wyświetlenia na czacie symulatora:</h3>
<h3>{{ $t('order-message.title') }}</h3>
<div class="message_body" v-html="fullOrderMessage"></div>
<div class="message_body" v-html="orderMessagePreview"></div>
<p class="message_info">
Po wygenerowaniu rozkazu skopiuj jego treść lub zapisz w pamięci przeglądarki za pomocą
przycisków poniżej
{{ $t('order-message.info') }}
</p>
<div class="message_actions">
<button class="g-button action" @click="saveOrder">Zapisz nowy rozkaz</button>
<button class="g-button action" @click="copyMessage">Kopiuj treść rozkazu</button>
<button class="g-button action icon" @click="saveOrder">
<LucideSave />
{{ $t('order-message.button-save') }}
</button>
<button class="g-button action icon" @click="copyMessage">
<LucideCopy />
{{ $t('order-message.button-copy') }}
</button>
<button
class="g-button action"
class="g-button action icon"
:data-disabled="!store.chosenLocalOrderId"
@click="updateOrder"
>
Zaktualizuj rozkaz
<span class="text--accent"
>{{ store.chosenLocalOrderId && `#${store.chosenLocalOrderId.split('-')[1]}` }}
<LucidePencil />
{{ $t('order-message.button-update') }}
<span class="text--accent" v-if="store.chosenLocalOrderId"
>#{{ store.chosenLocalOrderId.split('-')[1] }}
</span>
</button>
<button class="g-button action icon" @click="resetOrder">
<LucideRotateCcw />
{{ $t('order-message.button-reset') }}
</button>
</div>
<div class="message_checkboxes">
<label for="dark-mode" class="g-checkbox">
<input
type="checkbox"
name="dark-mode"
id="dark-mode"
v-model="store.orderDarkMode"
@change="onCheckboxChange"
/>
<span>Ciemny motyw rozkazu</span>
</label>
<label for="copy-increment" class="g-checkbox">
<input
type="checkbox"
@@ -43,7 +45,7 @@
v-model="incrementOnCopy"
@change="onCheckboxChange"
/>
<span>Aktualizuj numer rozkazu po skopiowaniu</span>
<span>{{ $t('order-options.update-number-on-copy') }}</span>
</label>
<label for="save-increment" class="g-checkbox">
@@ -54,7 +56,7 @@
v-model="incrementOnSave"
@change="onCheckboxChange"
/>
<span>Aktualizuj numer rozkazu po zapisaniu</span>
<span>{{ $t('order-options.update-number-on-save') }}</span>
</label>
<label for="update-date" class="g-checkbox">
@@ -65,7 +67,7 @@
v-model="updateDate"
@change="onCheckboxChange"
/>
<span>Aktualizuj godziny przy edycji</span>
<span>{{ $t('order-options.update-hours') }}</span>
</label>
</div>
@@ -77,23 +79,23 @@
<script lang="ts">
import { defineComponent } from 'vue';
import { useStore } from '../store/store';
import saveIcon from '../assets/icon-save.svg';
import orderStorageMixin from '../mixins/orderStorageMixin';
import orderValidationMixin from '../mixins/orderValidationMixin';
import { currentFormattedHours, currentFormattedMinutes } from '../utils/dateUtils';
import orderStorageMixin from '../../mixins/orderStorageMixin';
import orderValidationMixin from '../../mixins/orderValidationMixin';
import { useStore } from '../../store/store';
import { currentFormattedHours, currentFormattedMinutes } from '../../utils/dateUtils';
import { LucideCopy, LucidePencil, LucideRotateCcw, LucideSave } from 'lucide-vue-next';
import { setOrderToDefault } from '../../utils/orderUtils';
export default defineComponent({
name: 'OrderMessage',
components: { LucideCopy, LucidePencil, LucideRotateCcw, LucideSave },
mixins: [orderStorageMixin, orderValidationMixin],
data() {
return {
saveIcon,
actionMonit: '',
monitTimeout: undefined as number | undefined,
monitTimeout: null as number | null,
incrementOnSave: true,
incrementOnCopy: true,
@@ -108,14 +110,19 @@ export default defineComponent({
},
mounted() {
this.incrementOnSave = this.getOrderSetting('save-increment') === 'true';
this.incrementOnCopy = this.getOrderSetting('copy-increment') === 'true';
this.updateDate = this.getOrderSetting('update-date') === 'true';
this.incrementOnSave = this.getOrderSetting('save-increment') !== 'false';
this.incrementOnCopy = this.getOrderSetting('copy-increment') !== 'false';
this.updateDate = this.getOrderSetting('update-date') !== 'false';
},
computed: {
fullOrderMessage() {
return this.store.orderMessage + this.store.footerMessage;
},
// Replace all new line tags with <br> for preview and get rid of the first one (visible only on simulator's chat)
orderMessagePreview() {
return this.fullOrderMessage.replace(/\n/g, '<br>').replace('<br>', '');
}
},
@@ -135,25 +142,20 @@ export default defineComponent({
},
showActionMonit(text: string) {
if (this.monitTimeout) {
if (this.monitTimeout != null) {
this.actionMonit = '';
clearTimeout(this.monitTimeout);
setTimeout(() => {
this.actionMonit = text;
this.monitTimeout = window.setTimeout(() => {
this.actionMonit = '';
}, 5000);
}, 300);
return;
}, 100);
} else {
this.actionMonit = text;
}
this.actionMonit = text;
this.monitTimeout = window.setTimeout(() => {
this.actionMonit = '';
this.monitTimeout = null;
}, 5000);
},
@@ -165,27 +167,25 @@ export default defineComponent({
copyMessage() {
if (!navigator.clipboard)
return this.showActionMonit(
'Ups! Twoja przeglądarka musi być dosyć przestarzała, ponieważ nie obsługuje zapisu do schowka! :/'
);
return this.showActionMonit(this.$t('order-message.warning-outdated-clipboard'));
const hasAtLeastOneRow = /(\[ \d \])/g.test(this.fullOrderMessage);
const hasAllInputsFilled = !/_/g.test(this.store.orderMessage);
if (!hasAllInputsFilled)
return this.showActionMonit(
`<span class="text--warn">Wypełnij puste rubryki rozkazu przed jego skopiowaniem!</span>`
`<span class="text--warn">${this.$t('order-message.warning-fill-inputs')}</span>`
);
if (!hasAtLeastOneRow)
return this.showActionMonit(
`<span class="text--warn">Dodaj co najmniej jedną działkę rozkazu przed jego skopiowaniem!</span>`
`<span class="text--warn">${this.$t('order-message.warning-add-rows')}</span>`
);
const fieldsToCorrect = this.verifyOrderFields();
if (fieldsToCorrect.length > 0)
return this.showActionMonit(
`<span class="text--warn">Uzupełnij następujące rubryki na dole rozkazu przed jego skopiowaniem: ${fieldsToCorrect.join(
`<span class="text--warn">${this.$t('order-message.warning-fill-footer')} ${fieldsToCorrect.join(
', '
)}</span>`
);
@@ -194,9 +194,7 @@ export default defineComponent({
if (this.incrementOnCopy) this.incrementOrderNo();
this.showActionMonit(
'<b class="text--accent">Skopiowano!</b> Możesz teraz wkleić treść rozkazu na czacie symulatora!'
);
this.showActionMonit(this.$t('order-message.success-copy-html'));
},
saveOrder() {
@@ -205,18 +203,16 @@ export default defineComponent({
switch (savedOrderStatus) {
case -1:
this.showActionMonit(
'<span class="text--warn">Wypełnij numer rozkazu, numer pociągu i datę zanim dodasz rozkaz!</span>'
`<span class="text--warn">${this.$t('order-message.warning-fill-top')}</span>`
);
break;
case 0:
this.showActionMonit(
'<span class="text--warn">Ostatni zapisany rozkaz jest identyczny z obecnym!</span>'
`<span class="text--warn">${this.$t('order-message.warning-order-identical')}</span>`
);
break;
case 1:
this.showActionMonit(
'Zapisano treść <b class="text--accent">rozkazu</b> w pamięci przeglądarki!'
);
this.showActionMonit(this.$t('order-message.success-save-html'));
if (this.incrementOnSave) this.incrementOrderNo();
break;
@@ -232,29 +228,35 @@ export default defineComponent({
switch (updatedOrderStatus) {
case -1:
this.showActionMonit(
'<span class="text--warn">Wystąpił błąd podczas aktualizowania tego rozkazu! :/</span>'
`<span class="text--warn">${this.$t('order-message.error-update')}</span>`
);
break;
case 0:
this.showActionMonit(
'<span class="text--warn">Nie wybrałeś żadnego zapisanego rozkazu!</span>'
`<span class="text--warn">${this.$t('order-message.warning-no-order-selected')}</span>`
);
break;
case 1:
this.showActionMonit('Zaktualizowano treść <b class="text--accent">rozkazu</b>!');
this.showActionMonit(this.$t('order-message.success-update-html'));
break;
}
},
resetOrder() {
setOrderToDefault(this.store[this.store.chosenOrderType]);
}
}
});
</script>
<style lang="scss" scoped>
@use '../styles/colors';
@use '../../styles/colors';
.order-message {
overflow: auto;
h3 {
margin: 0;
margin-bottom: 1em;
@@ -267,8 +269,7 @@ export default defineComponent({
}
.message_body {
height: 250px;
overflow: auto;
height: 350px;
background-color: colors.$bgColLighter;
color: white;
@@ -287,10 +288,13 @@ export default defineComponent({
}
.message_actions {
display: flex;
align-items: center;
justify-content: center;
margin-top: 1em;
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 0.5em;
button.icon {
gap: 0.5em;
}
button img {
height: 2ch;
@@ -8,7 +8,9 @@
v-model="selectedSceneryId"
@change="selectOption"
>
<option :value="null" disabled>Sceneria</option>
<option :value="null" disabled>
{{ $t('order-train-picker.placeholder-scenery-name') }}
</option>
<option
v-for="scenery in filteredSceneries"
:value="`${scenery.stationName}|${scenery.stationHash}|${scenery.dispatcherName}|${scenery.region}`"
@@ -24,7 +26,9 @@
v-model="selectedRegion"
@change="selectOption"
>
<option :value="null" disabled>Region</option>
<option :value="null" disabled>
{{ $t('order-train-picker.placeholder-region-name') }}
</option>
<option v-for="region in regions" :value="region" :key="region">
{{ getRegionNameById(region) }}
</option>
@@ -44,7 +48,9 @@
v-model="selectedCheckpointName"
:disabled="!selectedScenery"
>
<option :value="null" disabled>Posterunek</option>
<option :value="null" disabled>
{{ $t('order-train-picker.placeholder-checkpoint-name') }}
</option>
<option :value="cp" v-for="cp in checkpointNameList" :key="cp">
{{ cp }}
</option>
@@ -57,19 +63,19 @@
id="fill-checkpoint"
v-model="fillCheckpointName"
/>
<span> Uzupełniaj skrót wybranego posterunku</span>
<span> {{ $t('order-train-picker.autofill-checkpoint-id') }}</span>
</label>
</div>
<div class="content">
<b v-if="!selectedSceneryId" class="text--accent">
Wybierz dyżurnego oraz scenerię, aby zobaczyć pociągi
{{ $t('order-train-picker.info') }}
</b>
<div v-else>
<div style="margin-bottom: 0.5em">
<h3 style="margin-bottom: 0.5em">Aktywne RJ i gracze na scenerii</h3>
<b class="text--accent">Kliknij na gracza, aby wypełnić obecny rozkaz jego danymi</b>
<h3 style="margin-bottom: 0.5em">{{ $t('order-train-picker.title') }}</h3>
<b class="text--accent">{{ $t('order-train-picker.subtitle') }}</b>
</div>
<ul class="train-list">
@@ -84,18 +90,18 @@
class="online-indicator"
></span>
<b>
<span>
{{ train.driverName }} &bull;
<span v-if="train.timetable" style="color: gold">{{
train.timetable.category
}}</span>
{{ train.trainNo }}
</b>
</span>
</button>
</li>
<li class="no-trains" v-if="sceneryTrains?.length == 0 && selectedSceneryId">
Brak graczy
{{ $t('order-train-picker.no-trains') }}
</li>
</ul>
</div>
@@ -105,16 +111,16 @@
<script lang="ts">
import { defineComponent } from 'vue';
import { useStore } from '../store/store';
import http from '../../http';
import { useStore } from '../../store/store';
import { API } from '../../types/apiTypes';
import { ISceneryData } from '../../types/dataTypes';
import {
currentFormattedDate,
currentFormattedHours,
currentFormattedMinutes
} from '../utils/dateUtils';
import http from '../http';
import { ISceneryData } from '../types/dataTypes';
import { API } from '../types/apiTypes';
import { getRegionNameById } from '../utils/sceneryUtils';
} from '../../utils/dateUtils';
import { getRegionNameById } from '../../utils/sceneryUtils';
export default defineComponent({
name: 'order-train-picker',
@@ -138,7 +144,7 @@ export default defineComponent({
},
created() {
this.fillCheckpointName = window.localStorage.getItem('fill-checkpoint') == 'true';
this.fillCheckpointName = window.localStorage.getItem('fill-checkpoint') !== 'false';
this.fetchSceneriesData();
},
@@ -240,7 +246,7 @@ export default defineComponent({
chosenOrder.header.trainNo = trainNo.toString();
chosenOrder.header.date = currentFormattedDate();
this.store.orderFooter.dispatcherName = this.selectedScenery.stationName;
this.store.orderFooter.dispatcherName = this.selectedScenery.dispatcherName;
this.store.orderFooter.stationName =
this.selectedCheckpointName?.split(',')[0] || this.selectedScenery.stationName;
this.store.orderFooter.hour = currentFormattedHours();
@@ -248,13 +254,14 @@ export default defineComponent({
if (this.fillCheckpointName) {
const sceneryAbbrev = this.sceneriesData?.find(
({ name }) => name === this.selectedSceneryId
({ name }) => name === this.selectedScenery!.stationName
)?.abbr;
this.store.orderFooter.checkpointName =
sceneryAbbrev || this.store.orderFooter.stationName.slice(0, 2);
}
this.store.orderMode = 'OrderMessage';
this.store.panelMode = 'OrderMessagePanel';
},
handleQueries() {
@@ -274,10 +281,9 @@ export default defineComponent({
if (queryScenery) {
this.selectedSceneryId = `${queryScenery.stationName}|${queryScenery.stationHash}|${queryScenery.dispatcherName}|${queryScenery.region}`;
console.log(this.selectedRegion);
this.selectOption();
this.store.orderMode = 'OrderTrainPicker';
this.store.panelMode = 'OrderTrainPickerPanel';
}
}
}
@@ -286,14 +292,14 @@ export default defineComponent({
</script>
<style lang="scss" scoped>
@use '../styles/colors';
@use '../../styles/colors';
.order-train-picker {
display: flex;
flex-direction: column;
align-items: center;
overflow: auto;
padding: 0 0.5em;
padding: 0.5em;
}
.options {
-3
View File
@@ -1,3 +0,0 @@
{
"orderS": ["D"]
}
+19
View File
@@ -0,0 +1,19 @@
import enLang from './locales/en.json';
import plLang from './locales/pl.json';
import { createI18n } from 'vue-i18n';
const i18n = createI18n({
locale: 'pl',
legacy: false,
warnHtmlMessage: false,
fallbackLocale: 'pl',
messages: {
en: enLang,
pl: plLang
},
enableLegacy: false
});
export default i18n;
+78
View File
@@ -0,0 +1,78 @@
{
"locale": {
"pl": "POL",
"en": "ENG"
},
"navbar": {
"OrderMessagePanel": "MESSAGE",
"OrderListPanel": "SAVED",
"OrderTrainPickerPanel": "TRAINS"
},
"update": {
"update-available-text": "New GeneraTOR version is available!",
"update-available-underline": "Click here to update!",
"title": "GeneraTOR update!",
"confirm": "ROGER THAT!",
"no-data": "No changelog available!",
"info-1": "This changelog will be available to see once again after clicking the version number in the footer",
"info-2": "The full app changelog available on <a href='https://github.com/Spythere/genera-tor' target='_blank'>the project's GitHub</a>"
},
"order-message": {
"title": "Message to display in the simulator's chatbox:",
"info": "Copy or save the content of the generated train order using buttons below:",
"button-save": "Save as new",
"button-copy": "Copy the message",
"button-update": "Update",
"button-reset": "Reset",
"warning-outdated-clipboard": "Oops! Your browser may be a little bit depraceted since it's not supporting saving data to the clipboard! :/",
"warning-fill-inputs": "Fill all the empty fields before copying the order!",
"warning-add-rows": "Add at least one row before copying the order!",
"warning-fill-footer": "Fill the following rows in the order's footer before copying it:",
"warning-fill-top": "Fill the order number, train number and date before saving it!",
"warning-order-identical": "Last saved order is identical as the current one!",
"warning-no-order-selected": "Choose the already saved order first!",
"error-update": "An error occurred while saving this order! :/",
"success-update-html": "Updated this <b class=\"text--accent\">order's</b> message!",
"success-save-html": "Saved <b class=\"text--accent\">order's</b> message in the browser memory!",
"success-copy-html": "<b class=\"text--accent\">Success!</b> You may paste the order message in the simulator's chatbox now!"
},
"order-footer": {
"field-stationName": "station",
"field-checkpointName": "checkpoint",
"field-hour": "hour",
"field-minutes": "minute",
"field-dispatcherName": "dispatcher",
"field-secondaryDispatcherName": "ordering dispatcher",
"field-dispatcherOrSecondaryName": "dispatcher (or ordering dispatcher)"
},
"order-options": {
"dark-mode": "Order dark theme",
"update-number-on-copy": "Update order number on copy",
"update-number-on-save": "Update order number on save",
"update-hours": "Update order hour on edit"
},
"order-list": {
"title": "Saved train orders",
"order-title": "Order \"{orderName}\" no. {orderNo} for train no. {trainNo}",
"no-saved-orders": "No saved orders!",
"order-added": "Added:",
"order-updated": "Updated:",
"button-order-select": "Select",
"button-order-remove": "Remove"
},
"order-train-picker": {
"placeholder-scenery-name": "Scenery name",
"placeholder-region-name": "Region",
"placeholder-checkpoint-name": "Checkpoint name",
"autofill-checkpoint-id": "Autofill checkpoint's abbreviation",
"info": "Select scenery name to display active trains",
"title": "Active timetables and trains on the scenery",
"subtitle": "Click on the user below to fill the current order with their information",
"no-trains": "No trains to display"
},
"migrate-info": {
"line-1": "GeneraTOR is being moved to a new domain - {0}! You can still use the current website, but it will no longer be updated and will be shut down in the nearest future!",
"link": "https://generator-td2.spythere.eu/",
"accept-btn": "ROGER THAT!"
}
}
+78
View File
@@ -0,0 +1,78 @@
{
"locale": {
"pl": "POL",
"en": "ENG"
},
"update": {
"update-available-text": "Nowa wersja GeneraTORa dostępna!",
"update-available-underline": "Kliknij, aby odświeżyć aplikację!",
"title": "Aktualizacja GeneraTORa!",
"no-data": "Brak dostępnego changelogu!",
"confirm": "Przyjąłem!",
"info-1": "Ten changelog będzie zawsze dostępny po kliknięciu numeru wersji w stopce strony",
"info-2": "Pełny changelog dostępny na <a href='https://github.com/Spythere/genera-tor' target='_blank'>GitHubie projektu</a>"
},
"navbar": {
"OrderMessagePanel": "WIADOMOŚĆ",
"OrderListPanel": "ZAPISANE",
"OrderTrainPickerPanel": "POCIĄGI"
},
"order-message": {
"title": "Wiadomość do wyświetlenia na czacie symulatora:",
"info": "Po wygenerowaniu rozkazu skopiuj jego treść lub zapisz w pamięci przeglądarki za pomocą przycisków poniżej:",
"button-save": "Zapisz nowy",
"button-copy": "Skopiuj treść",
"button-update": "Zaktualizuj",
"button-reset": "Zresetuj",
"warning-outdated-clipboard": "Ups! Twoja przeglądarka musi być dosyć przestarzała, ponieważ nie obsługuje zapisu do schowka! :/",
"warning-fill-inputs": "Wypełnij puste rubryki rozkazu przed jego skopiowaniem!",
"warning-add-rows": "Dodaj co najmniej jedną działkę rozkazu przed jego skopiowaniem!",
"warning-fill-footer": "Uzupełnij następujące rubryki na dole rozkazu przed jego skopiowaniem:",
"warning-fill-top": "Wypełnij numer rozkazu, numer pociągu i datę zanim dodasz rozkaz!",
"warning-order-identical": "Ostatni zapisany rozkaz jest identyczny z obecnym!",
"warning-no-order-selected": "Wybierz rozkaz, który chcesz zaktualizować!",
"error-update": "Wystąpił błąd podczas aktualizowania tego rozkazu! :/",
"success-update-html": "Zaktualizowano treść <b class=\"text--accent\">rozkazu</b>!",
"success-save-html": "Zapisano treść <b class=\"text--accent\">rozkazu</b> w pamięci przeglądarki!",
"success-copy-html": "<b class=\"text--accent\">Skopiowano!</b> Możesz teraz wkleić treść rozkazu na czacie symulatora!"
},
"order-footer": {
"field-stationName": "stacja",
"field-checkpointName": "posterunek",
"field-hour": "godzina",
"field-minutes": "minuta",
"field-dispatcherName": "dyżurny ruchu",
"field-secondaryDispatcherName": "z polecenia dyżurnego ruchu",
"field-dispatcherOrSecondaryName": "dyżurny ruchu (lub z polecenia dyżurnego ruchu)"
},
"order-options": {
"dark-mode": "Ciemny motyw bloczka rozkazu",
"update-number-on-copy": "Aktualizuj numer rozkazu po skopiowaniu",
"update-number-on-save": "Aktualizuj numer rozkazu po zapisaniu",
"update-hours": "Aktualizuj godziny przy edycji"
},
"order-list": {
"title": "Zapisane rozkazy pisemne",
"no-saved-orders": "Brak zapisanych rozkazów!",
"order-title": "Rozkaz \"{orderName}\" nr {orderNo} dla pociągu nr {trainNo}",
"order-added": "Dodano:",
"order-updated": "Zaktualizowano:",
"button-order-select": "Wybierz",
"button-order-remove": "Usuń"
},
"order-train-picker": {
"placeholder-scenery-name": "Sceneria",
"placeholder-region-name": "Region",
"placeholder-checkpoint-name": "Posterunek",
"autofill-checkpoint-id": "Uzupełniaj skrót wybranego posterunku",
"info": "Wybierz dyżurnego oraz scenerię, aby zobaczyć pociągi",
"title": "Aktywne RJ i gracze na scenerii",
"subtitle": "Kliknij na gracza, aby wypełnić obecny rozkaz jego danymi",
"no-trains": "Brak pociągów do wyświetlenia"
},
"migrate-info": {
"line-1": "GeneraTOR zostaje przeniesiony na nową domenę - {0}! Możesz korzystać z obecnej strony, jednak nie będzie ona otrzymywać już aktualizacji i w przyszłości zostanie wyłączona!",
"link": "https://generator-td2.spythere.eu/",
"accept-btn": "PRZYJĄŁEM!"
}
}
+3 -1
View File
@@ -3,4 +3,6 @@ import App from './App.vue';
import router from './router';
import { createPinia } from 'pinia';
createApp(App).use(router).use(createPinia()).mount('#app');
import i18n from './i18n';
createApp(App).use(router).use(i18n).use(createPinia()).mount('#app');
+53
View File
@@ -0,0 +1,53 @@
export default class StorageManager {
static registerStorage(name: string) {
window.localStorage.setItem(name, '1');
}
static unregisterStorage(name: string) {
window.localStorage.removeItem(name);
}
static isRegistered(name: string) {
return window.localStorage.getItem(name) ? true : false;
}
static setBooleanValue(key: string, val: boolean) {
window.localStorage.setItem(key, val.toString());
}
static setNumericValue(key: string, val: number) {
window.localStorage.setItem(key, val.toString());
}
static setStringValue(key: string, val: string) {
window.localStorage.setItem(key, val);
}
static setValue(key: string, val: any) {
if (typeof val == 'boolean') this.setBooleanValue(key, val);
else if (typeof val == 'number') this.setNumericValue(key, val);
else if (typeof val == 'string') this.setStringValue(key, val);
else this.setStringValue(key, val);
}
static removeValue(key: string) {
window.localStorage.removeItem(key);
}
static getValue(key: string) {
return window.localStorage.getItem(key);
}
static getBooleanValue(key: string): boolean {
return window.localStorage.getItem(key) === 'true' ? true : false;
}
static getStringValue(key: string): string {
return window.localStorage.getItem(key) || '';
}
static getNumericValue(key: string): number {
const itemValue = window.localStorage.getItem(key);
return itemValue ? parseInt(itemValue) : 0;
}
}
+3 -3
View File
@@ -14,7 +14,7 @@ export default defineComponent({
const messageArray = [];
if (footer.stationName) messageArray.push(`stacja: ${footer.stationName}`);
messageArray.push(`stacja: ${footer.stationName ?? ''}`);
if (footer.checkpointName) messageArray.push(`posterunek: ${footer.checkpointName}`);
if (footer.hour) messageArray.push(`godz. ${footer.hour}`);
if (footer.minutes) messageArray.push(`min. ${footer.minutes}`);
@@ -22,9 +22,9 @@ export default defineComponent({
if (footer.secondaryDispatcherName)
messageArray.push(`z polecenia dyżurnego ruchu ${footer.secondaryDispatcherName}`);
this.store.footerMessage = ` <b>|</b> ${messageArray.join(
this.store.footerMessage = `\n--------\n${messageArray.join(
', '
)} <b>|</b> Rozkaz otrzymałem, maszynista: (potwierdzić otrzymanie rozkazu)`;
)}\n--------\nRozkaz otrzymałem, maszynista: <i>(potwierdzić otrzymanie rozkazu)</i>`;
}
}
});
+1 -1
View File
@@ -157,7 +157,7 @@ export default defineComponent({
this.store.chosenOrderType = localOrder.orderType;
this.store.chosenLocalOrderId = localOrder.id;
this.store.orderMode = 'OrderMessage';
this.store.panelMode = 'OrderMessagePanel';
}
}
});
+1 -1
View File
@@ -4,7 +4,7 @@ import { useStore } from '../store/store';
export default defineComponent({
setup() {
return {
store: useStore()
store: useStore(),
};
},
+22 -2
View File
@@ -1,21 +1,33 @@
import { defineStore } from 'pinia';
import { IOrderN, IOrderO, IOrderS, TOrder } from '../types/orderTypes';
import { IOrderN, IOrderO, IOrderS, TOrder, TPanel } from '../types/orderTypes';
import {
currentFormattedDate,
currentFormattedHours,
currentFormattedMinutes
} from '../utils/dateUtils';
import i18n from '../i18n';
import StorageManager from '../managers/storageManager';
export const useStore = defineStore('store', {
state: () => {
return {
currentAppLocale: 'pl',
appUpdateData: {
version: '',
changelog: '',
releaseURL: ''
},
isMigrationInfoOpen: false,
updateCardOpen: false,
helperModalOpen: false,
orderDarkMode: false,
chosenOrderType: 'orderN' as TOrder,
chosenLocalOrderId: '',
orderMode: 'OrderMessage',
panelMode: 'OrderMessagePanel' as TPanel,
orderFooter: {
stationName: '',
@@ -205,5 +217,13 @@ export const useStore = defineStore('store', {
]
} as IOrderS
};
},
actions: {
changeLang(lang: string) {
i18n.global.locale.value = lang as typeof i18n.global.locale.value;
this.currentAppLocale = lang;
StorageManager.setStringValue('lang', lang);
}
}
});
+23 -16
View File
@@ -1,24 +1,31 @@
@font-face {
font-family: 'Libre Franklin';
src: url('/fonts/LibreFranklin-Bold.woff2') format('woff2');
font-weight: 800;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Libre Franklin';
src: url('/fonts/LibreFranklin-Regular.woff2') format('woff2');
font-style: normal;
font-weight: 400;
src: url('/fonts/libre-franklin-regular.woff2') format('woff2');
}
@font-face {
font-display: swap;
font-family: 'Libre Franklin';
font-style: normal;
font-weight: 500;
font-style: normal;
font-display: swap;
}
src: url('/fonts/libre-franklin-500.woff2') format('woff2');
}
@font-face {
@font-face {
font-display: swap;
font-family: 'Libre Franklin';
src: url('/fonts/LibreFranklin-SemiBold.woff2') format('woff2');
font-weight: 700;
font-style: normal;
font-display: swap;
}
font-weight: 700;
src: url('/fonts/libre-franklin-700.woff2') format('woff2');
}
@font-face {
font-display: swap;
font-family: 'Libre Franklin';
font-style: normal;
font-weight: 800;
src: url('/fonts/libre-franklin-800.woff2') format('woff2');
}
+9 -15
View File
@@ -1,21 +1,8 @@
@use 'fonts';
@use 'colors';
// Global scrollbar style
::-webkit-scrollbar {
width: 15px;
}
::-webkit-scrollbar-track {
background: #333;
}
::-webkit-scrollbar-thumb {
background: #888;
}
::-webkit-scrollbar-thumb:hover {
background: #555;
[data-theme='dark'] {
color-scheme: dark;
}
body,
@@ -70,6 +57,7 @@ button.g-button {
&.action {
background-color: colors.$bgColDarker;
padding: 0.5em;
color: white;
&:focus-visible {
outline: 2px solid colors.$accentCol;
@@ -107,6 +95,12 @@ button.g-button {
color: colors.$accentCol;
}
}
&.icon {
display: flex;
justify-content: center;
align-items: center;
}
}
// Text styles
+1
View File
@@ -1,4 +1,5 @@
export type TOrder = 'orderO' | 'orderS' | 'orderN';
export type TPanel = 'OrderMessagePanel' | 'OrderListPanel' | 'OrderTrainPickerPanel';
export interface LocalStorageOrder {
id: string;
+197
View File
@@ -0,0 +1,197 @@
import { IOrderN, IOrderO, IOrderS, TOrder } from '../types/orderTypes';
import { currentFormattedDate } from './dateUtils';
const orderDefaults = {
orderN: {
header: {
orderNo: '1',
trainNo: '',
date: ''
},
rows: [
{
enabled: false,
from: '',
to: '',
trackNo: '',
trackNo2: ''
},
{
enabled: false,
option1: 'sygnału "Nakaz Jazdy"',
option2: 'lewy',
option3: 'lewy',
signal1: '',
signal2: '',
signal3: '',
signalType: 'wyjazdowego',
checkbox: 'checkbox-2a',
direction1: '',
direction2: '',
trackNoFrom: '',
trackNoTo1: '',
trackNoTo2: ''
},
{
enabled: false,
option1: 'Jazda',
option2: 'pociąg',
direction: '',
toKilometer: '',
trackNo: '',
untilHour: '',
untilMin: ''
},
{
enabled: false,
trackNo: '',
optionStation: 'stację',
stationName: '',
checkbox: 'checkbox-4a',
side: 'lewej'
},
{
enabled: false,
trackNo: '',
direction: '',
stationType: 'stację',
stationName: '',
on: ''
},
{
enabled: false,
content: '',
twoWay: {
enabled: false,
from: '',
to: '',
trackNo: ''
}
}
]
},
orderS: {
header: {
orderNo: '1',
trainNo: '',
for: 'pociągu',
date: ''
},
rows: [
{
enabled: false,
option1: 'sygnału "nakaz jazdy"',
optionSignal: 'wyjazdowego',
radio1: 'radio-1a-1',
signal1: '',
trackNo: ''
},
{
enabled: false,
signalType: 'wyjazdowego',
signal1: '',
signal2: '',
signal3: '',
trackNo: ''
},
{
enabled: false,
from: '',
to: '',
trackNo: '',
trainNo: '',
arrivedTo: '',
hour: ''
},
{
enabled: false,
content: '',
w5: {
enabled: false,
maxHour: '',
borderType: 'wskaźnik przetaczania W5',
tmName: '',
maxKm: '',
returnWay: 'sygnał ręczny "Do mnie"',
trackNo: ''
}
}
]
},
orderO: {
header: {
orderNo: '1',
trainNo: '',
date: ''
},
orderList: [
{
name: '',
from: '',
to: '',
vmax: '',
jo: false,
reason: ''
},
{
name: '',
from: '',
to: '',
vmax: '',
jo: false,
reason: ''
},
{
name: '',
from: '',
to: '',
vmax: '',
jo: false,
reason: ''
},
{
name: '',
from: '',
to: '',
vmax: '',
jo: false,
reason: ''
},
{
name: '',
from: '',
to: '',
vmax: '',
jo: false,
reason: ''
}
],
other: ''
}
};
export function getOrderType(order: IOrderN | IOrderO | IOrderS): TOrder {
if ('rows' in order && 'for' in order.header) return 'orderS';
else if ('rows' in order) return 'orderN';
return 'orderO';
}
export function setOrderToDefault(order: IOrderN | IOrderO | IOrderS) {
const orderType = getOrderType(order);
const defaultOrderObjectCopy = JSON.parse(JSON.stringify(orderDefaults[orderType]));
Object.assign(order, defaultOrderObjectCopy);
// Update date in the header
order.header.date = currentFormattedDate();
}
+111 -99
View File
@@ -2,30 +2,45 @@
<!-- <OrderHelper v-if="store.helperModalOpen" /> -->
<div class="home">
<div class="home_container">
<div class="order_container">
<SideBar />
<OrderVue />
</div>
<div class="home-container">
<Order />
<div class="message_container">
<div class="message_nav">
<span v-for="(action, i) in navActions" :key="action.mode">
<b v-if="i > 0">&bull;</b>
<div class="panel-container">
<div class="panel-nav">
<button
key="OrderMessagePanel"
class="g-button"
:data-active="store.panelMode == 'OrderMessagePanel'"
@click="selectPanelMode('OrderMessagePanel')"
>
<MessageSquareTextIcon :size="20" />
{{ t(`navbar.OrderMessagePanel`) }}
</button>
<button
class="g-button option"
:data-active="store.orderMode == action.mode"
@click="selectOrderMode(action.mode)"
key="OrderListPanel"
class="g-button"
:data-active="store.panelMode == 'OrderListPanel'"
@click="selectPanelMode('OrderListPanel')"
>
{{ action.value }}
<BookMarkedIcon :size="20" />
{{ t(`navbar.OrderListPanel`) }}
</button>
<button
key="OrderTrainPickerPanel"
class="g-button"
:data-active="store.panelMode == 'OrderTrainPickerPanel'"
@click="selectPanelMode('OrderTrainPickerPanel')"
>
<TrainFrontIcon :size="20" />
{{ t(`navbar.OrderTrainPickerPanel`) }}
</button>
</span>
</div>
<transition name="order-anim" mode="out-in">
<keep-alive>
<Component :is="orderModeComponent" />
<Component :is="panelComponent" />
</keep-alive>
</transition>
</div>
@@ -33,70 +48,42 @@
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import OrderVue from '../components/Order.vue';
import SideBar from '../components/SideBar.vue';
import OrderMessage from '../components/OrderMessage.vue';
import OrderList from '../components/OrderList.vue';
<script lang="ts" setup>
import { computed } from 'vue';
import { useI18n } from 'vue-i18n';
import { useStore } from '../store/store';
import OrderHelper from '../components/OrderHelper.vue';
import OrderTrainPicker from '../components/OrderTrainPicker.vue';
import OrderMessagePanel from '../components/Panels/OrderMessagePanel.vue';
import OrderListPanel from '../components/Panels/OrderListPanel.vue';
import OrderTrainPickerPanel from '../components/Panels/OrderTrainPickerPanel.vue';
import SideBar from '../components/App/SideBar.vue';
import Order from '../components/Orders/Order.vue';
import { BookMarkedIcon, MessageSquareTextIcon, TrainFrontIcon } from 'lucide-vue-next';
import { TPanel } from '../types/orderTypes';
export default defineComponent({
components: { OrderVue, SideBar, OrderHelper },
const store = useStore();
const { t } = useI18n();
data() {
return {
navActions: [
{
mode: 'OrderMessage',
value: 'TREŚĆ ROZKAZU'
},
{
mode: 'OrderList',
value: 'ZAPISANE ROZKAZY'
},
{
mode: 'OrderTrainPicker',
value: 'POCIĄGI'
}
]
};
},
function selectPanelMode(mode: TPanel) {
store.panelMode = mode;
}
methods: {
selectOrderMode(mode: string) {
this.store.orderMode = mode;
}
},
setup() {
return {
store: useStore()
};
},
computed: {
orderModeComponent() {
switch (this.store.orderMode) {
case 'OrderMessage':
return OrderMessage;
case 'OrderList':
return OrderList;
case 'OrderTrainPicker':
return OrderTrainPicker;
const panelComponent = computed(() => {
switch (store.panelMode) {
case 'OrderListPanel':
return OrderListPanel;
case 'OrderTrainPickerPanel':
return OrderTrainPickerPanel;
case 'OrderMessagePanel':
default:
return OrderMessage;
}
}
return OrderMessagePanel;
}
});
</script>
<style lang="scss" scoped>
@use '../styles/colors';
.home {
min-height: 100vh;
overflow-x: auto;
display: flex;
@@ -104,52 +91,77 @@ export default defineComponent({
align-items: center;
width: 100%;
}
.home_container {
display: flex;
flex-wrap: wrap;
.home-container {
display: grid;
grid-template-columns: 600px 500px;
justify-content: center;
gap: 2em 1em;
padding: 0.5em;
padding: 1em;
width: 100%;
@media screen and (max-width: 650px) {
@media screen and (max-width: 1150px) {
grid-template-columns: auto;
padding: 1em 0.5em;
}
}
.order_container {
width: 100%;
max-width: 600px;
display: flex;
align-items: start;
@media screen and (max-width: 650px) {
flex-direction: column;
}
}
.message_container {
width: 100%;
max-width: 500px;
}
.panel-container {
display: grid;
grid-template-rows: auto 1fr;
grid-template-rows: auto auto 1fr;
color-scheme: dark;
height: 95vh;
padding: 2px;
max-width: 800px;
height: calc(100vh - 5em);
overflow: auto;
}
.panel-nav {
display: flex;
justify-content: center;
align-items: center;
flex-wrap: wrap;
gap: 0.25em;
margin-bottom: 1.5em;
}
.panel-nav > button {
position: relative;
display: flex;
justify-content: center;
align-items: center;
gap: 0.5em;
min-width: 8em;
padding: 0.25em 0.5em;
&:focus-visible {
outline: 1px solid white;
}
.message_nav {
display: flex;
align-items: center;
justify-content: center;
&::before {
position: absolute;
content: '';
bottom: -3px;
left: 50%;
transform: translateX(-50%);
flex-wrap: wrap;
width: 0;
height: 3px;
margin-bottom: 2em;
transition: all 0.25s;
background-color: colors.$accentCol;
}
&[data-active='true'] {
color: colors.$accentCol;
}
&[data-active='true']::before {
width: 100%;
}
}
</style>
+1 -1
View File
@@ -23,7 +23,7 @@ export default defineConfig({
VitePWA({
registerType: 'prompt',
workbox: {
globPatterns: ['**/*.{js,css,html,png,svg,img}'],
globPatterns: ['**/*.{js,css,html,png,svg,img,woff2,ico}'],
runtimeCaching: [
{
urlPattern: /^https:\/\/stacjownik.spythere.eu\/\/api\/getSceneries/i,
+158 -130
View File
@@ -963,26 +963,26 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3"
integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==
"@intlify/core-base@9.8.0":
version "9.8.0"
resolved "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.8.0.tgz"
integrity sha512-UxaSZVZ1DwqC/CltUZrWZNaWNhfmKtfyV4BJSt/Zt4Or/fZs1iFj0B+OekYk1+MRHfIOe3+x00uXGQI4PbO/9g==
"@intlify/core-base@11.2.8":
version "11.2.8"
resolved "https://registry.yarnpkg.com/@intlify/core-base/-/core-base-11.2.8.tgz#083551bdd79b415476f282ded84f5ddc5fad75c1"
integrity sha512-nBq6Y1tVkjIUsLsdOjDSJj4AsjvD0UG3zsg9Fyc+OivwlA/oMHSKooUy9tpKj0HqZ+NWFifweHavdljlBLTwdA==
dependencies:
"@intlify/message-compiler" "9.8.0"
"@intlify/shared" "9.8.0"
"@intlify/message-compiler" "11.2.8"
"@intlify/shared" "11.2.8"
"@intlify/message-compiler@9.8.0":
version "9.8.0"
resolved "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.8.0.tgz"
integrity sha512-McnYWhcoYmDJvssVu6QGR0shqlkJuL1HHdi5lK7fNqvQqRYaQ4lSLjYmZxwc8tRNMdIe9/KUKfyPxU9M6yCtNQ==
"@intlify/message-compiler@11.2.8":
version "11.2.8"
resolved "https://registry.yarnpkg.com/@intlify/message-compiler/-/message-compiler-11.2.8.tgz#3d967c07a36a8d6060730c1d3a2d40e3caaf07b3"
integrity sha512-A5n33doOjmHsBtCN421386cG1tWp5rpOjOYPNsnpjIJbQ4POF0QY2ezhZR9kr0boKwaHjbOifvyQvHj2UTrDFQ==
dependencies:
"@intlify/shared" "9.8.0"
"@intlify/shared" "11.2.8"
source-map-js "^1.0.2"
"@intlify/shared@9.8.0":
version "9.8.0"
resolved "https://registry.npmjs.org/@intlify/shared/-/shared-9.8.0.tgz"
integrity sha512-TmgR0RCLjzrSo+W3wT0ALf9851iFMlVI9EYNGeWvZFUQTAJx0bvfsMlPdgVtV1tDNRiAfhkFsMKu6jtUY1ZLKQ==
"@intlify/shared@11.2.8":
version "11.2.8"
resolved "https://registry.yarnpkg.com/@intlify/shared/-/shared-11.2.8.tgz#30815afda2acd859cefdbb97cf59e7f819f32611"
integrity sha512-l6e4NZyUgv8VyXXH4DbuucFOBmxLF56C/mqh2tvApbzl2Hrhi1aTDcuv5TKdxzfHYmpO3UB0Cz04fgDT9vszfw==
"@jridgewell/gen-mapping@^0.3.5":
version "0.3.8"
@@ -1045,94 +1045,94 @@
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
"@parcel/watcher-android-arm64@2.5.1":
version "2.5.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz#507f836d7e2042f798c7d07ad19c3546f9848ac1"
integrity sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==
"@parcel/watcher-android-arm64@2.5.4":
version "2.5.4"
resolved "https://registry.yarnpkg.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.4.tgz#88c67bde2c3efa997a0b1fea540080c6ade0322c"
integrity sha512-hoh0vx4v+b3BNI7Cjoy2/B0ARqcwVNrzN/n7DLq9ZB4I3lrsvhrkCViJyfTj/Qi5xM9YFiH4AmHGK6pgH1ss7g==
"@parcel/watcher-darwin-arm64@2.5.1":
version "2.5.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz#3d26dce38de6590ef79c47ec2c55793c06ad4f67"
integrity sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==
"@parcel/watcher-darwin-arm64@2.5.4":
version "2.5.4"
resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.4.tgz#d9dc037cff8a4ab7839a79c5287a6e6660f7ab27"
integrity sha512-kphKy377pZiWpAOyTgQYPE5/XEKVMaj6VUjKT5VkNyUJlr2qZAn8gIc7CPzx+kbhvqHDT9d7EqdOqRXT6vk0zw==
"@parcel/watcher-darwin-x64@2.5.1":
version "2.5.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz#99f3af3869069ccf774e4ddfccf7e64fd2311ef8"
integrity sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==
"@parcel/watcher-darwin-x64@2.5.4":
version "2.5.4"
resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.4.tgz#da0e13e16ee6d378242e2cfb469d72667624383a"
integrity sha512-UKaQFhCtNJW1A9YyVz3Ju7ydf6QgrpNQfRZ35wNKUhTQ3dxJ/3MULXN5JN/0Z80V/KUBDGa3RZaKq1EQT2a2gg==
"@parcel/watcher-freebsd-x64@2.5.1":
version "2.5.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz#14d6857741a9f51dfe51d5b08b7c8afdbc73ad9b"
integrity sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==
"@parcel/watcher-freebsd-x64@2.5.4":
version "2.5.4"
resolved "https://registry.yarnpkg.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.4.tgz#feb7cc9ec680bae3e91dddcdb4fe1c399ed52cc1"
integrity sha512-Dib0Wv3Ow/m2/ttvLdeI2DBXloO7t3Z0oCp4bAb2aqyqOjKPPGrg10pMJJAQ7tt8P4V2rwYwywkDhUia/FgS+Q==
"@parcel/watcher-linux-arm-glibc@2.5.1":
version "2.5.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz#43c3246d6892381db473bb4f663229ad20b609a1"
integrity sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==
"@parcel/watcher-linux-arm-glibc@2.5.4":
version "2.5.4"
resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.4.tgz#fa4e9cf8228c8c433e2f035e8b16aa299d892a78"
integrity sha512-I5Vb769pdf7Q7Sf4KNy8Pogl/URRCKu9ImMmnVKYayhynuyGYMzuI4UOWnegQNa2sGpsPSbzDsqbHNMyeyPCgw==
"@parcel/watcher-linux-arm-musl@2.5.1":
version "2.5.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz#663750f7090bb6278d2210de643eb8a3f780d08e"
integrity sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==
"@parcel/watcher-linux-arm-musl@2.5.4":
version "2.5.4"
resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.4.tgz#9ee6792e2d8810af9871ee5bbc2aa04e0b079d62"
integrity sha512-kGO8RPvVrcAotV4QcWh8kZuHr9bXi9a3bSZw7kFarYR0+fGliU7hd/zevhjw8fnvIKG3J9EO5G6sXNGCSNMYPQ==
"@parcel/watcher-linux-arm64-glibc@2.5.1":
version "2.5.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz#ba60e1f56977f7e47cd7e31ad65d15fdcbd07e30"
integrity sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==
"@parcel/watcher-linux-arm64-glibc@2.5.4":
version "2.5.4"
resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.4.tgz#624c6d874d99afa79305720f96a0c233d4ad7fde"
integrity sha512-KU75aooXhqGFY2W5/p8DYYHt4hrjHZod8AhcGAmhzPn/etTa+lYCDB2b1sJy3sWJ8ahFVTdy+EbqSBvMx3iFlw==
"@parcel/watcher-linux-arm64-musl@2.5.1":
version "2.5.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz#f7fbcdff2f04c526f96eac01f97419a6a99855d2"
integrity sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==
"@parcel/watcher-linux-arm64-musl@2.5.4":
version "2.5.4"
resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.4.tgz#5341e88b9e645d31c015ed40f384e60e49bd74d2"
integrity sha512-Qx8uNiIekVutnzbVdrgSanM+cbpDD3boB1f8vMtnuG5Zau4/bdDbXyKwIn0ToqFhIuob73bcxV9NwRm04/hzHQ==
"@parcel/watcher-linux-x64-glibc@2.5.1":
version "2.5.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz#4d2ea0f633eb1917d83d483392ce6181b6a92e4e"
integrity sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==
"@parcel/watcher-linux-x64-glibc@2.5.4":
version "2.5.4"
resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.4.tgz#be5bcc49d3f6d21cc81bb531970a05d3721e385c"
integrity sha512-UYBQvhYmgAv61LNUn24qGQdjtycFBKSK3EXr72DbJqX9aaLbtCOO8+1SkKhD/GNiJ97ExgcHBrukcYhVjrnogA==
"@parcel/watcher-linux-x64-musl@2.5.1":
version "2.5.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz#277b346b05db54f55657301dd77bdf99d63606ee"
integrity sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==
"@parcel/watcher-linux-x64-musl@2.5.4":
version "2.5.4"
resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.4.tgz#bffd3895b1f0cc8fd1436e409fd65d0a901281c0"
integrity sha512-YoRWCVgxv8akZrMhdyVi6/TyoeeMkQ0PGGOf2E4omODrvd1wxniXP+DBynKoHryStks7l+fDAMUBRzqNHrVOpg==
"@parcel/watcher-win32-arm64@2.5.1":
version "2.5.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz#7e9e02a26784d47503de1d10e8eab6cceb524243"
integrity sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==
"@parcel/watcher-win32-arm64@2.5.4":
version "2.5.4"
resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.4.tgz#7fb8aedea5b34ba97a01e1555929d01f4eb72fe4"
integrity sha512-iby+D/YNXWkiQNYcIhg8P5hSjzXEHaQrk2SLrWOUD7VeC4Ohu0WQvmV+HDJokZVJ2UjJ4AGXW3bx7Lls9Ln4TQ==
"@parcel/watcher-win32-ia32@2.5.1":
version "2.5.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz#2d0f94fa59a873cdc584bf7f6b1dc628ddf976e6"
integrity sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==
"@parcel/watcher-win32-ia32@2.5.4":
version "2.5.4"
resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.4.tgz#f7f94ebdb21dedf37b12e030a82d4211798a1c26"
integrity sha512-vQN+KIReG0a2ZDpVv8cgddlf67J8hk1WfZMMP7sMeZmJRSmEax5xNDNWKdgqSe2brOKTQQAs3aCCUal2qBHAyg==
"@parcel/watcher-win32-x64@2.5.1":
version "2.5.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz#ae52693259664ba6f2228fa61d7ee44b64ea0947"
integrity sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==
"@parcel/watcher-win32-x64@2.5.4":
version "2.5.4"
resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.4.tgz#8d895c9723f7fffdf4b360fd1becf1b6bcb571df"
integrity sha512-3A6efb6BOKwyw7yk9ro2vus2YTt2nvcd56AuzxdMiVOxL9umDyN5PKkKfZ/gZ9row41SjVmTVQNWQhaRRGpOKw==
"@parcel/watcher@^2.4.1":
version "2.5.1"
resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.5.1.tgz#342507a9cfaaf172479a882309def1e991fb1200"
integrity sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==
version "2.5.4"
resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.5.4.tgz#a6575b0a018b4e263589c1e7bc2ceb73c1ee84de"
integrity sha512-WYa2tUVV5HiArWPB3ydlOc4R2ivq0IDrlqhMi3l7mVsFEXNcTfxYFPIHXHXIh/ca/y/V5N4E1zecyxdIBjYnkQ==
dependencies:
detect-libc "^1.0.3"
detect-libc "^2.0.3"
is-glob "^4.0.3"
micromatch "^4.0.5"
node-addon-api "^7.0.0"
picomatch "^4.0.3"
optionalDependencies:
"@parcel/watcher-android-arm64" "2.5.1"
"@parcel/watcher-darwin-arm64" "2.5.1"
"@parcel/watcher-darwin-x64" "2.5.1"
"@parcel/watcher-freebsd-x64" "2.5.1"
"@parcel/watcher-linux-arm-glibc" "2.5.1"
"@parcel/watcher-linux-arm-musl" "2.5.1"
"@parcel/watcher-linux-arm64-glibc" "2.5.1"
"@parcel/watcher-linux-arm64-musl" "2.5.1"
"@parcel/watcher-linux-x64-glibc" "2.5.1"
"@parcel/watcher-linux-x64-musl" "2.5.1"
"@parcel/watcher-win32-arm64" "2.5.1"
"@parcel/watcher-win32-ia32" "2.5.1"
"@parcel/watcher-win32-x64" "2.5.1"
"@parcel/watcher-android-arm64" "2.5.4"
"@parcel/watcher-darwin-arm64" "2.5.4"
"@parcel/watcher-darwin-x64" "2.5.4"
"@parcel/watcher-freebsd-x64" "2.5.4"
"@parcel/watcher-linux-arm-glibc" "2.5.4"
"@parcel/watcher-linux-arm-musl" "2.5.4"
"@parcel/watcher-linux-arm64-glibc" "2.5.4"
"@parcel/watcher-linux-arm64-musl" "2.5.4"
"@parcel/watcher-linux-x64-glibc" "2.5.4"
"@parcel/watcher-linux-x64-musl" "2.5.4"
"@parcel/watcher-win32-arm64" "2.5.4"
"@parcel/watcher-win32-ia32" "2.5.4"
"@parcel/watcher-win32-x64" "2.5.4"
"@pkgr/utils@^2.4.2":
version "2.4.2"
@@ -1321,11 +1321,11 @@
integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
"@types/node@^22.13.10":
version "22.13.10"
resolved "https://registry.yarnpkg.com/@types/node/-/node-22.13.10.tgz#df9ea358c5ed991266becc3109dc2dc9125d77e4"
integrity sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==
version "22.19.7"
resolved "https://registry.yarnpkg.com/@types/node/-/node-22.19.7.tgz#434094ee1731ae76c16083008590a5835a8c39c1"
integrity sha512-MciR4AKGHWl7xwxkBa6xUGxQJ4VBOmPTF7sL+iGzuahOFaO0jHCsuEfS80pan1ef4gWId1oWOweIhrDEYLuaOw==
dependencies:
undici-types "~6.20.0"
undici-types "~6.21.0"
"@types/resolve@1.20.2":
version "1.20.2"
@@ -1337,6 +1337,11 @@
resolved "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz"
integrity sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==
"@types/showdown@^2.0.6":
version "2.0.6"
resolved "https://registry.yarnpkg.com/@types/showdown/-/showdown-2.0.6.tgz#3d7affd5f971b4a17783ec2b23b4ad3b97477b7e"
integrity sha512-pTvD/0CIeqe4x23+YJWlX2gArHa8G0J0Oh6GKaVXV7TAeickpkkZiNOgFcFcmLQ5lB/K0qBJL1FtRYltBfbGCQ==
"@types/trusted-types@^2.0.2":
version "2.0.7"
resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.7.tgz#baccb07a970b91707df3a3e8ba6896c57ead2d11"
@@ -1688,12 +1693,12 @@ available-typed-arrays@^1.0.7:
possible-typed-array-names "^1.0.0"
axios@^1.6.2:
version "1.8.4"
resolved "https://registry.yarnpkg.com/axios/-/axios-1.8.4.tgz#78990bb4bc63d2cae072952d374835950a82f447"
integrity sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==
version "1.13.2"
resolved "https://registry.yarnpkg.com/axios/-/axios-1.13.2.tgz#9ada120b7b5ab24509553ec3e40123521117f687"
integrity sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==
dependencies:
follow-redirects "^1.15.6"
form-data "^4.0.0"
form-data "^4.0.4"
proxy-from-env "^1.1.0"
babel-plugin-polyfill-corejs2@^0.4.10:
@@ -1861,6 +1866,11 @@ commander@^2.20.0:
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
commander@^9.0.0:
version "9.5.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30"
integrity sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==
common-tags@^1.8.0:
version "1.8.2"
resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.2.tgz#94ebb3c076d26032745fd54face7f688ef5ac9c6"
@@ -2011,10 +2021,10 @@ delayed-stream@~1.0.0:
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
detect-libc@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==
detect-libc@^2.0.3:
version "2.1.2"
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.1.2.tgz#689c5dcdc1900ef5583a4cb9f6d7b473742074ad"
integrity sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==
dir-glob@^3.0.1:
version "3.0.1"
@@ -2443,9 +2453,9 @@ flatted@^3.2.9:
integrity sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==
follow-redirects@^1.15.6:
version "1.15.9"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1"
integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==
version "1.15.11"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.11.tgz#777d73d72a92f8ec4d2e410eb47352a56b8e8340"
integrity sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==
for-each@^0.3.3, for-each@^0.3.5:
version "0.3.5"
@@ -2454,14 +2464,15 @@ for-each@^0.3.3, for-each@^0.3.5:
dependencies:
is-callable "^1.2.7"
form-data@^4.0.0:
version "4.0.2"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.2.tgz#35cabbdd30c3ce73deb2c42d3c8d3ed9ca51794c"
integrity sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==
form-data@^4.0.4:
version "4.0.5"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.5.tgz#b49e48858045ff4cbf6b03e1805cebcad3679053"
integrity sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.8"
es-set-tostringtag "^2.1.0"
hasown "^2.0.2"
mime-types "^2.1.12"
fs-extra@^9.0.1:
@@ -2701,9 +2712,9 @@ ignore@^5.2.4:
integrity sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==
immutable@^5.0.2:
version "5.0.3"
resolved "https://registry.yarnpkg.com/immutable/-/immutable-5.0.3.tgz#aa037e2313ea7b5d400cd9298fa14e404c933db1"
integrity sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==
version "5.1.4"
resolved "https://registry.yarnpkg.com/immutable/-/immutable-5.1.4.tgz#e3f8c1fe7b567d56cf26698f31918c241dae8c1f"
integrity sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==
import-fresh@^3.2.1:
version "3.3.1"
@@ -3111,6 +3122,11 @@ lru-cache@^5.1.1:
dependencies:
yallist "^3.0.2"
lucide-vue-next@^0.562.0:
version "0.562.0"
resolved "https://registry.yarnpkg.com/lucide-vue-next/-/lucide-vue-next-0.562.0.tgz#a4cc08c2d00b9664c768e5da76e6634212a02a23"
integrity sha512-LN0BLGKMFulv0lnfK29r14DcngRUhIqdcaL0zXTt2o0oS9odlrjCGaU3/X9hIihOjjN8l8e+Y9G/famcNYaI7Q==
magic-string@^0.25.0, magic-string@^0.25.7:
version "0.25.9"
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c"
@@ -3140,7 +3156,7 @@ merge2@^1.3.0, merge2@^1.4.1:
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
micromatch@^4.0.4, micromatch@^4.0.5, micromatch@^4.0.8:
micromatch@^4.0.4, micromatch@^4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202"
integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==
@@ -3387,6 +3403,11 @@ picomatch@^4.0.2:
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab"
integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==
picomatch@^4.0.3:
version "4.0.3"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.3.tgz#796c76136d1eead715db1e7bad785dedd695a042"
integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==
pinia@^2.1.7:
version "2.3.1"
resolved "https://registry.yarnpkg.com/pinia/-/pinia-2.3.1.tgz#54c476675b72f5abcfafa24a7582531ea8c23d94"
@@ -3430,9 +3451,9 @@ prettier-linter-helpers@^1.0.0:
fast-diff "^1.1.2"
prettier@^3.0.3:
version "3.5.3"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.5.3.tgz#4fc2ce0d657e7a02e602549f053b239cb7dfe1b5"
integrity sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==
version "3.8.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.8.1.tgz#edf48977cf991558f4fcbd8a3ba6015ba2a3a173"
integrity sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==
pretty-bytes@^5.3.0:
version "5.6.0"
@@ -3659,9 +3680,9 @@ safe-regex-test@^1.1.0:
is-regex "^1.2.1"
sass@^1.69.5:
version "1.86.0"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.86.0.tgz#f49464fb6237a903a93f4e8760ef6e37a5030114"
integrity sha512-zV8vGUld/+mP4KbMLJMX7TyGCuUp7hnkOScgCMsWuHtns8CWBoz+vmEhoGMXsaJrbUP8gj+F1dLvVe79sK8UdA==
version "1.97.2"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.97.2.tgz#e515a319092fd2c3b015228e3094b40198bff0da"
integrity sha512-y5LWb0IlbO4e97Zr7c3mlpabcbBtS+ieiZ9iwDooShpFKWXf62zz5pEPdwrLYm+Bxn1fnbwFGzHuCLSA9tBmrw==
dependencies:
chokidar "^4.0.0"
immutable "^5.0.2"
@@ -3729,6 +3750,13 @@ shebang-regex@^3.0.0:
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
showdown@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/showdown/-/showdown-2.1.0.tgz#1251f5ed8f773f0c0c7bfc8e6fd23581f9e545c5"
integrity sha512-/6NVYu4U819R2pUIk79n67SYgJHWCce0a5xTP979WbNp0FL9MN1I1QK662IDU1b6JzKTvmhgI7T7JYIxBi3kMQ==
dependencies:
commander "^9.0.0"
side-channel-list@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad"
@@ -4043,9 +4071,9 @@ typed-array-length@^1.0.7:
reflect.getprototypeof "^1.0.6"
typescript@^5.3.3:
version "5.8.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.2.tgz#8170b3702f74b79db2e5a96207c15e65807999e4"
integrity sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==
version "5.9.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.9.3.tgz#5b4f59e15310ab17a216f5d6cf53ee476ede670f"
integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==
unbox-primitive@^1.1.0:
version "1.1.0"
@@ -4057,10 +4085,10 @@ unbox-primitive@^1.1.0:
has-symbols "^1.1.0"
which-boxed-primitive "^1.1.1"
undici-types@~6.20.0:
version "6.20.0"
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.20.0.tgz#8171bf22c1f588d1554d55bf204bc624af388433"
integrity sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==
undici-types@~6.21.0:
version "6.21.0"
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb"
integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==
unicode-canonical-property-names-ecmascript@^2.0.0:
version "2.0.1"
@@ -4172,19 +4200,19 @@ vue-eslint-parser@^9.3.1, vue-eslint-parser@^9.4.3:
lodash "^4.17.21"
semver "^7.3.6"
vue-i18n@9.8.0:
version "9.8.0"
resolved "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.8.0.tgz"
integrity sha512-Izho+6PYjejsTq2mzjcRdBZ5VLRQoSuuexvR8029h5CpN03FYqiqBrShMyf2I1DKkN6kw/xmujcbvC+4QybpsQ==
vue-i18n@11:
version "11.2.8"
resolved "https://registry.yarnpkg.com/vue-i18n/-/vue-i18n-11.2.8.tgz#f431b583134776dcf59e59250c5231e4eaed8404"
integrity sha512-vJ123v/PXCZntd6Qj5Jumy7UBmIuE92VrtdX+AXr+1WzdBHojiBxnAxdfctUFL+/JIN+VQH4BhsfTtiGsvVObg==
dependencies:
"@intlify/core-base" "9.8.0"
"@intlify/shared" "9.8.0"
"@intlify/core-base" "11.2.8"
"@intlify/shared" "11.2.8"
"@vue/devtools-api" "^6.5.0"
vue-router@^4.2.5:
version "4.5.0"
resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-4.5.0.tgz#58fc5fe374e10b6018f910328f756c3dae081f14"
integrity sha512-HDuk+PuH5monfNuY+ct49mNmkCRK4xJAV9Ts4z9UFc4rzdDnxQLyCMGGc8pKhZhHTVzfanpNwB/lwqevcBwI4w==
version "4.6.4"
resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-4.6.4.tgz#a0a9cb9ef811a106d249e4bb9313d286718020d8"
integrity sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==
dependencies:
"@vue/devtools-api" "^6.6.4"