diff --git a/src/App.scss b/src/App.scss
index 5c1ee6c..89e94db 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -213,6 +213,7 @@
font-weight: bold;
padding: 0.1em 0.5em;
color: paleturquoise;
+
}
.options {
diff --git a/src/App.vue b/src/App.vue
index e03c2d7..3b8ee71 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -42,7 +42,7 @@
-
+
@@ -124,6 +124,20 @@ export default defineComponent({
trainList() {
return this.store.trainList.filter((train) => train.online);
},
+
+ computedRegions() {
+ return this.options.regions.map((region) => {
+ const regionStationCount =
+ this.store.apiData.stations?.filter((station) => station.region == region.id && station.isOnline).length || 0;
+ const regionTrainCount = this.store.apiData.trains?.filter((train) => train.region == region.id && train.online).length || 0;
+
+ return {
+ id: region.id,
+ value: `${region.value}
${regionStationCount} / ${regionTrainCount}
`,
+ selectedValue: region.value,
+ };
+ });
+ },
},
data: () => ({
@@ -141,6 +155,8 @@ export default defineComponent({
pl: require('@/assets/icon-pl.svg'),
error: require('@/assets/icon-error.svg'),
dollar: require('@/assets/icon-dollar.svg'),
+ dispatcher: require('@/assets/icon-dispatcher.svg'),
+ train: require('@/assets/icon-train.svg'),
discord: require('@/assets/icon-discord.png'),
},
}),
diff --git a/src/components/App/StatusIndicator.vue b/src/components/App/StatusIndicator.vue
index 7d7332f..caffdf5 100644
--- a/src/components/App/StatusIndicator.vue
+++ b/src/components/App/StatusIndicator.vue
@@ -204,10 +204,18 @@ export default defineComponent({
deep: true,
handler(statuses: StoreState['dataStatuses']) {
+ const connectionStatus = statuses.connection;
const sceneryDataStatus = statuses.sceneries;
const trainsDataStatus = statuses.trains;
const dispatcherDataStatus = statuses.dispatchers;
+ if (connectionStatus == DataStatus.Error) {
+ this.setSignalStatus(connectionStatus);
+ this.indicator.status = connectionStatus;
+ this.indicator.message = 'data-status.S1a-connection';
+ return;
+ }
+
if (sceneryDataStatus == DataStatus.Error) {
this.setSignalStatus(sceneryDataStatus);
this.indicator.status = sceneryDataStatus;
diff --git a/src/components/Global/SelectBox.vue b/src/components/Global/SelectBox.vue
index fc22aa0..3c44b0e 100644
--- a/src/components/Global/SelectBox.vue
+++ b/src/components/Global/SelectBox.vue
@@ -1,8 +1,9 @@
-
+
@@ -15,9 +16,7 @@
>
@@ -36,6 +35,7 @@ import { computed, defineComponent, Ref, ref } from '@vue/runtime-core';
interface Item {
id: string;
value: string;
+ selectedValue?: string;
}
export default defineComponent({
@@ -193,8 +193,6 @@ ul.options {
z-index: 10;
width: 100%;
-
- margin-top: 0.25em;
}
li.option {
@@ -207,10 +205,11 @@ li.option {
-moz-appearance: none;
appearance: none;
border: none;
+ outline: none;
&:focus + span {
color: $accentCol;
- font-weight: bold;
+ font-weight: 800;
}
}
@@ -229,7 +228,7 @@ li.option {
background-color: hsla(0, 0%, 20%, 0.95);
}
- padding: 0.75em 0;
+ padding: 0.5em 0;
width: 100%;
diff --git a/src/components/JournalView/JournalDispatchers.vue b/src/components/JournalView/JournalDispatchers.vue
index cac7aae..55e34f0 100644
--- a/src/components/JournalView/JournalDispatchers.vue
+++ b/src/components/JournalView/JournalDispatchers.vue
@@ -149,11 +149,7 @@ export default defineComponent({
statsCardOpen: false,
}),
- setup(props) {
- watch(props, (val) => {
- console.log(val.dispatcherName);
- });
-
+ setup() {
const historyDataStatus: Ref<{ status: DataStatus; error: string | null }> = ref({
status: DataStatus.Loading,
error: null,
diff --git a/src/components/SceneryView/SceneryInfo/SceneryInfoUserList.vue b/src/components/SceneryView/SceneryInfo/SceneryInfoUserList.vue
index 6cafa10..f724377 100644
--- a/src/components/SceneryView/SceneryInfo/SceneryInfoUserList.vue
+++ b/src/components/SceneryView/SceneryInfo/SceneryInfoUserList.vue
@@ -79,7 +79,6 @@ $terminated: salmon;
$disconnected: slategray;
.info-user-list {
- padding: 0.5em;
ul {
display: flex;
diff --git a/src/components/SceneryView/SceneryTimetable.vue b/src/components/SceneryView/SceneryTimetable.vue
index ce20156..03a6ab5 100644
--- a/src/components/SceneryView/SceneryTimetable.vue
+++ b/src/components/SceneryView/SceneryTimetable.vue
@@ -95,9 +95,12 @@
{{ timestampToString(scheduledTrain.stopInfo.arrivalTimestamp) }}
-
{{
- timestampToString(scheduledTrain.stopInfo.arrivalTimestamp)
- }}
+
+ {{
+ timestampToString(scheduledTrain.stopInfo.arrivalTimestamp)
+ }}
+
+
{{ timestampToString(scheduledTrain.stopInfo.arrivalRealTimestamp) }}
({{ scheduledTrain.stopInfo.arrivalDelay > 0 ? '+' : ''
@@ -108,11 +111,22 @@
-
- {{ scheduledTrain.stopInfo.stopTime }}
- {{ scheduledTrain.stopInfo.stopType || 'pt' }}
+
+
+ {{ scheduledTrain.stopInfo.stopTime }}
+ {{ scheduledTrain.stopInfo.stopType || 'pt' }}
+
+
+
+
+
+
+
+
+ {{ scheduledTrain.arrivingLine }}
+ {{ scheduledTrain.arrivingLine && scheduledTrain.departureLine && '>' }}
+ {{ scheduledTrain.departureLine }}
-
@@ -125,9 +139,11 @@
{{ timestampToString(scheduledTrain.stopInfo.departureTimestamp) }}
-
{{
- timestampToString(scheduledTrain.stopInfo.departureTimestamp)
- }}
+
+ {{
+ timestampToString(scheduledTrain.stopInfo.departureTimestamp)
+ }}
+
{{ timestampToString(scheduledTrain.stopInfo.departureRealTimestamp) }}
@@ -201,13 +217,15 @@ export default defineComponent({
station.onlineInfo?.scheduledTrains ||
[];
+ if (!scheduledTrains) return [];
+
return (
- scheduledTrains?.sort((a, b) => {
+ scheduledTrains.sort((a, b) => {
if (a.stopStatusID > b.stopStatusID) return 1;
- else if (a.stopStatusID < b.stopStatusID) return -1;
+ if (a.stopStatusID < b.stopStatusID) return -1;
if (a.stopInfo.arrivalTimestamp > b.stopInfo.arrivalTimestamp) return 1;
- else if (a.stopInfo.arrivalTimestamp < b.stopInfo.arrivalTimestamp) return -1;
+ if (a.stopInfo.arrivalTimestamp < b.stopInfo.arrivalTimestamp) return -1;
return a.stopInfo.departureTimestamp > b.stopInfo.departureTimestamp ? 1 : -1;
}) || []
@@ -459,10 +477,15 @@ h3.timetable-header {
position: relative;
display: flex;
flex-direction: column;
+ font-size: 0.85em;
+
+ padding: 0.3em 0;
+
+ .stop-line {
+ margin-top: 0.25em;
+ }
.stop-time {
- font-size: 0.85em;
- // position: absolute;
transform: translateY(-0.25em);
}
}
diff --git a/src/components/TrainsView/TrainSchedule.vue b/src/components/TrainsView/TrainSchedule.vue
index 1058d28..22109c4 100644
--- a/src/components/TrainsView/TrainSchedule.vue
+++ b/src/components/TrainsView/TrainSchedule.vue
@@ -123,7 +123,7 @@ export default defineComponent({
if (lastMajorConfirmed + 1 >= props.train.timetableData!.followingStops.length) return activeMinorStopList;
for (let i = lastMajorConfirmed + 1; i < props.train.timetableData!.followingStops.length; i++) {
- if (props.train.timetableData!.followingStops[i].stopNameRAW.includes('po.')) activeMinorStopList.push(i);
+ if (/po\.|sbl/gi.test(props.train.timetableData!.followingStops[i].stopNameRAW)) activeMinorStopList.push(i);
else break;
}
@@ -144,6 +144,7 @@ export default defineComponent({
begin: stop.beginsHere,
end: stop.terminatesHere,
delayed: stop.departureDelay > 0,
+ sbl: /sbl/gi.test(stop.stopName),
[stop.stopType.replaceAll(', ', '-')]:
stop.stopType.match(new RegExp('ph|pm|pt')) && !stop.confirmed && !stop.beginsHere,
'minor-stop-active': this.activeMinorStops.includes(index),
@@ -232,6 +233,10 @@ ul.stock-list {
display: flex;
align-items: center;
+
+ &.misc {
+ background: gray;
+ }
}
.stop-comment {
@@ -272,6 +277,17 @@ ul.stop_list > li.stop {
padding: 0 0.5em;
+ &.sbl {
+ .stop-name,
+ .stop-date {
+ opacity: 0.7;
+ }
+
+ .stop-name {
+ background-color: #333;
+ }
+ }
+
&[class*='ph'] > .stop_info > .indicator {
border-color: $stopNameClr;
}
diff --git a/src/components/TrainsView/TrainTable.vue b/src/components/TrainsView/TrainTable.vue
index 2b849aa..71fb8a1 100644
--- a/src/components/TrainsView/TrainTable.vue
+++ b/src/components/TrainsView/TrainTable.vue
@@ -183,9 +183,9 @@ export default defineComponent({
padding: 1em 0;
margin: 1em 0;
- font-size: 1.35em;
+ font-size: 1.5em;
- background: var(--clr-bg);
+ background: #333;
}
img.train-image {
diff --git a/src/locales/en.json b/src/locales/en.json
index e86bf69..c4e9bde 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -11,7 +11,7 @@
"migration-confirm": "Roger that!"
},
"data-status": {
- "S1a-connection": "S1a signal
Cannot connect with SWDR API service!",
+ "S1a-connection": "S1a signal
Cannot connect with Stacjownik API service!",
"S1a-sceneries": "S1a signal
Cannot load online stations data!",
"S2": "S2 signal
All data loaded successfully!",
"S3": "S3 signal
Loading data...",
@@ -108,7 +108,7 @@
"hour": "h",
"no-limit": "NO LIMIT",
"include-selected": "INCLUDE SELECTED",
- "save": "🗸 SAVE FILTERS",
+ "save": "↵ SAVE FILTERS",
"reset": "RESET FILTERS",
"close": "CLOSE FILTERS"
},
diff --git a/src/locales/pl.json b/src/locales/pl.json
index 2b76150..f1e32cc 100644
--- a/src/locales/pl.json
+++ b/src/locales/pl.json
@@ -12,7 +12,7 @@
},
"data-status": {
- "S1a-connection": "Sygnał S1a
Błąd podczas próby połączenia się z serwisem SWDR!",
+ "S1a-connection": "Sygnał S1a
Błąd podczas próby połączenia się z API Stacjownika!",
"S1a-sceneries": "Sygnał S1a
Błąd podczas pobierania danych o sceneriach online!",
"S2": "Sygnał S2
Pomyślnie załadowano dane!",
"S3": "Sygnał S3
Pobieranie danych...",
@@ -109,7 +109,7 @@
"hour": " godz.",
"no-limit": "BEZ LIMITU",
"include-selected": "POKAÅ» ZAZNACZONE",
- "save": "🗸 ZAPISZ FILTRY",
+ "save": "↵ ZAPISZ FILTRY",
"reset": "RESETUJ FILTRY",
"close": "ZAMKNIJ FILTRY"
},
diff --git a/src/mixins/trainInfoMixin.ts b/src/mixins/trainInfoMixin.ts
index 3ae046e..fa6cb1b 100644
--- a/src/mixins/trainInfoMixin.ts
+++ b/src/mixins/trainInfoMixin.ts
@@ -65,8 +65,7 @@ export default defineComponent({
else if (
i > 0 &&
i < stops.length - 1 &&
- !stop.stopNameRAW.includes('po.') &&
- !stop.stopNameRAW.includes('SBL')
+ !/po\.|sbl/gi.test(stop.stopNameRAW)
)
acc.push(`${stop.stopName}`);
return acc;
diff --git a/src/scripts/interfaces/ScheduledTrain.ts b/src/scripts/interfaces/ScheduledTrain.ts
index 079a42a..f138d8c 100644
--- a/src/scripts/interfaces/ScheduledTrain.ts
+++ b/src/scripts/interfaces/ScheduledTrain.ts
@@ -15,6 +15,9 @@ export default interface ScheduledTrain {
prevStationName: string;
nextStationName: string;
+ arrivingLine: string | null;
+ departureLine: string | null;
+
stopLabel: string;
stopStatus: string;
stopStatusID: number;
diff --git a/src/scripts/utils/storeUtils.ts b/src/scripts/utils/storeUtils.ts
index 8c9182b..e65ff3b 100644
--- a/src/scripts/utils/storeUtils.ts
+++ b/src/scripts/utils/storeUtils.ts
@@ -1,37 +1,38 @@
-import ScheduledTrain from "../interfaces/ScheduledTrain";
-import Train from "../interfaces/Train";
-import TrainStop from "../interfaces/TrainStop";
+import ScheduledTrain from '../interfaces/ScheduledTrain';
+import Train from '../interfaces/Train';
+import TrainStop from '../interfaces/TrainStop';
-export const getLocoURL = (locoType: string): string => (`https://rj.td2.info.pl/dist/img/thumbnails/${locoType.includes("EN") ? locoType + "rb" : locoType}.png`)
+export const getLocoURL = (locoType: string): string =>
+ `https://rj.td2.info.pl/dist/img/thumbnails/${locoType.includes('EN') ? locoType + 'rb' : locoType}.png`;
export const getStatusID = (stationStatus: any): string => {
- if (!stationStatus) return "unknown";
- if (stationStatus == -1) return "not-signed";
+ if (!stationStatus) return 'unknown';
+ if (stationStatus == -1) return 'not-signed';
const statusCode = stationStatus[2];
const statusTimestamp = stationStatus[3];
switch (statusCode) {
case 0:
- if (statusTimestamp - Date.now() > 21000000) return "no-limit";
+ if (statusTimestamp - Date.now() > 21000000) return 'no-limit';
- return "online";
+ return 'online';
case 1:
- return "brb";
+ return 'brb';
case 2:
- if (statusTimestamp == 0) return "ending";
+ if (statusTimestamp == 0) return 'ending';
break;
case 3:
- return "no-space";
+ return 'no-space';
default:
break;
}
- return "unavailable";
+ return 'unavailable';
};
export const getStatusTimestamp = (stationStatus: any): number => {
@@ -59,10 +60,10 @@ export const getStatusTimestamp = (stationStatus: any): number => {
export const parseSpawns = (spawnString: string) => {
if (!spawnString) return [];
- if (spawnString === "NO_SPAWN") return [];
+ if (spawnString === 'NO_SPAWN') return [];
- return spawnString.split(";").map(spawn => {
- const spawnArray = spawn.split(",");
+ return spawnString.split(';').map((spawn) => {
+ const spawnArray = spawn.split(',');
const spawnName = spawnArray[6] ? spawnArray[6] : spawnArray[0];
const spawnLength = parseInt(spawnArray[2]);
@@ -73,40 +74,39 @@ export const parseSpawns = (spawnString: string) => {
export const getTimestamp = (date: string | null): number => (date ? new Date(date).getTime() : 0);
export const getTrainStopStatus = (stopInfo: TrainStop, currentStationName: string, stationName: string) => {
- let stopStatus = "",
- stopLabel = "",
+ let stopStatus = '',
+ stopLabel = '',
stopStatusID = -1;
if (stopInfo.terminatesHere && stopInfo.confirmed) {
- stopStatus = "terminated";
- stopLabel = "Skończył bieg";
+ stopStatus = 'terminated';
+ stopLabel = 'Skończył bieg';
stopStatusID = 5;
} else if (!stopInfo.terminatesHere && stopInfo.confirmed && currentStationName == stationName) {
- stopStatus = "departed";
- stopLabel = "Odprawiony";
+ stopStatus = 'departed';
+ stopLabel = 'Odprawiony';
stopStatusID = 2;
} else if (!stopInfo.terminatesHere && stopInfo.confirmed && currentStationName != stationName) {
- stopStatus = "departed-away";
- stopLabel = "Odjechał";
+ stopStatus = 'departed-away';
+ stopLabel = 'Odjechał';
stopStatusID = 4;
} else if (currentStationName == stationName && !stopInfo.stopped) {
- stopStatus = "online";
- stopLabel = "Na stacji";
+ stopStatus = 'online';
+ stopLabel = 'Na stacji';
stopStatusID = 0;
} else if (currentStationName == stationName && stopInfo.stopped) {
- stopStatus = "stopped";
- stopLabel = "Postój";
+ stopStatus = 'stopped';
+ stopLabel = 'Postój';
stopStatusID = 1;
} else if (currentStationName != stationName) {
- stopStatus = "arriving";
- stopLabel = "W drodze";
+ stopStatus = 'arriving';
+ stopLabel = 'W drodze';
stopStatusID = 3;
}
return { stopStatus, stopLabel, stopStatusID };
};
-
export function getScheduledTrain(train: Train, trainStopIndex: number, stationName: string): ScheduledTrain {
const timetable = train.timetableData!;
const followingStops = timetable.followingStops;
@@ -114,22 +114,48 @@ export function getScheduledTrain(train: Train, trainStopIndex: number, stationN
const trainStopStatus = getTrainStopStatus(trainStop, train.currentStationName, stationName);
- let prevStationName = "", nextStationName = "";
+ let prevStationName = '',
+ nextStationName = '';
for (let i = trainStopIndex - 1; i >= 0; i--) {
- if (followingStops[i].stopName.startsWith("")) {
+ if (followingStops[i].stopName.startsWith('')) {
prevStationName = followingStops[i].stopNameRAW;
break;
}
}
for (let i = trainStopIndex + 1; i < followingStops.length; i++) {
- if (followingStops[i].stopName.startsWith("")) {
+ if (followingStops[i].stopName.startsWith('')) {
nextStationName = followingStops[i].stopNameRAW;
break;
}
}
+ let departureLine: string | null = trainStop.departureLine;
+ let arrivingLine: string | null = trainStop.arrivalLine;
+
+ for (let i = trainStopIndex; i < followingStops.length; i++) {
+ const currentStop = followingStops[i];
+
+ if (currentStop.departureLine == null) break;
+
+ if (!/-|_|it|sbl/gi.test(currentStop.departureLine)) {
+ departureLine = currentStop.departureLine;
+ break;
+ }
+ }
+
+ for (let i = trainStopIndex; i >= 0; i--) {
+ const currentStop = followingStops[i];
+
+ if (currentStop.arrivalLine == null) break;
+
+ if (!/-|_|it|sbl/gi.test(currentStop.arrivalLine)) {
+ arrivingLine = currentStop.arrivalLine;
+ break;
+ }
+ }
+
return {
trainNo: train.trainNo,
driverName: train.driverName,
@@ -139,13 +165,16 @@ export function getScheduledTrain(train: Train, trainStopIndex: number, stationN
category: timetable.category,
beginsAt: timetable.followingStops[0].stopNameRAW,
terminatesAt: timetable.followingStops[timetable.followingStops.length - 1].stopNameRAW,
-
+
nextStationName,
prevStationName,
stopInfo: trainStop,
stopLabel: trainStopStatus.stopLabel,
stopStatus: trainStopStatus.stopStatus,
- stopStatusID: trainStopStatus.stopStatusID
- }
-}
\ No newline at end of file
+ stopStatusID: trainStopStatus.stopStatusID,
+
+ arrivingLine,
+ departureLine,
+ };
+}
diff --git a/src/store/store.ts b/src/store/store.ts
index d9f6e65..1b8c439 100644
--- a/src/store/store.ts
+++ b/src/store/store.ts
@@ -56,7 +56,7 @@ export const useStore = defineStore('store', {
setTrainsOnlineData() {
const { trains } = this.apiData;
- if (!trains) return [];
+ if (!trains) return [];
this.trainList = trains
.filter(
@@ -334,6 +334,12 @@ export const useStore = defineStore('store', {
transports: ['websocket', 'polling'],
rememberUpgrade: true,
reconnection: true,
+ timeout: 10000
+ });
+
+ socket.on('connect_error', (err) => {
+ this.dataStatuses.connection = DataStatus.Error;
+ this.webSocket = undefined;
});
socket.on('UPDATE', (data: APIData) => {
@@ -347,6 +353,7 @@ export const useStore = defineStore('store', {
});
this.webSocket = socket;
+ this.dataStatuses.connection = DataStatus.Loaded;
},
async connectToAPI() {
@@ -370,10 +377,11 @@ export const useStore = defineStore('store', {
return;
}
+
this.dataStatuses.sceneries = DataStatus.Loaded;
this.dataStatuses.trains = !this.apiData.trains ? DataStatus.Warning : DataStatus.Loaded;
this.dataStatuses.dispatchers = !this.apiData.dispatchers ? DataStatus.Warning : DataStatus.Loaded;
-
+
this.setTrainsOnlineData();
this.setStationsOnlineInfo();
},
diff --git a/src/views/SceneryView.vue b/src/views/SceneryView.vue
index 08e04fa..d663637 100644
--- a/src/views/SceneryView.vue
+++ b/src/views/SceneryView.vue
@@ -146,8 +146,8 @@ $sceneryBgCol: #333;
&-wrapper {
position: relative;
- width: 75%;
- max-width: 1200px;
+ width: 100%;
+ max-width: 1100px;
@include midScreen {
width: 100%;