lokalne fonty; poprawki offline i cachingu pwa

This commit is contained in:
2023-12-21 19:27:27 +01:00
parent 0c6b55146f
commit 2027b85450
23 changed files with 168 additions and 82 deletions
-5
View File
@@ -50,11 +50,6 @@
name="twitter:image"
content="https://raw.githubusercontent.com/Spythere/api/main/thumbnails/stacjownik.jpg"
/>
<link
href="https://fonts.googleapis.com/css2?family=Quicksand:wght@500;700&display=swap"
rel="stylesheet"
/>
</head>
<body>
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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+34 -34
View File
@@ -37,7 +37,6 @@ import { defineComponent, watch } from 'vue';
import Clock from './components/App/Clock.vue';
import packageInfo from '.././package.json';
import { regions } from './data/options.json';
import { useMainStore } from './store/mainStore';
import StatusIndicator from './components/App/StatusIndicator.vue';
@@ -46,6 +45,7 @@ import AppHeader from './components/App/AppHeader.vue';
import axios from 'axios';
import StorageManager from './managers/storageManager';
import { useApiStore } from './store/apiStore';
import { Status } from './typings/common';
export default defineComponent({
components: {
@@ -66,26 +66,10 @@ export default defineComponent({
}),
created() {
this.loadLang();
this.apiStore.setupAPI();
this.store.isOffline = !window.navigator.onLine;
window.addEventListener('offline', () => {
this.store.isOffline = true;
this.apiStore.activeData = undefined;
this.apiStore.setDataStatuses();
});
window.addEventListener('online', () => {
this.store.isOffline = false;
});
this.init();
},
async mounted() {
this.setReleaseURL();
watch(
() => this.store.blockScroll,
(value) => {
@@ -95,23 +79,39 @@ export default defineComponent({
);
},
watch: {
'$route.query.region': {
immediate: true,
handler(regionQuery: string) {
if (regionQuery) {
this.store.region.id =
regions.find(
(reg) =>
reg.id == regionQuery.toLocaleLowerCase() ||
reg.value.toLocaleLowerCase() == regionQuery.toLocaleLowerCase()
)?.id || 'eu';
}
}
}
},
methods: {
init() {
this.loadLang();
this.setReleaseURL();
this.setupOfflineHandling();
this.apiStore.setupAPI();
},
setupOfflineHandling() {
this.store.isOffline = !window.navigator.onLine;
if (this.store.isOffline) this.handleOfflineMode();
window.addEventListener('offline', this.handleOfflineMode);
window.addEventListener('online', this.handleOnlineMode);
},
handleOfflineMode() {
this.store.isOffline = true;
this.apiStore.stopActiveDataScheduler();
this.apiStore.activeData = undefined;
this.apiStore.dataStatuses.connection = Status.Data.Offline;
},
handleOnlineMode() {
this.store.isOffline = false;
this.apiStore.setupAPI();
},
changeLang(lang: string) {
this.$i18n.locale = lang;
this.currentLang = lang;
+4 -4
View File
@@ -240,9 +240,9 @@ export default defineComponent({
const trainsDataStatus = statuses.trains;
const dispatcherDataStatus = statuses.dispatchers;
if (this.store.isOffline) {
this.setSignalStatus(Status.Data.Initialized);
this.indicator.status = Status.Data.Initialized;
if (connectionStatus == Status.Data.Offline) {
this.setSignalStatus(Status.Data.Offline);
this.indicator.status = Status.Data.Offline;
this.indicator.message = 'data-status.S1-offline';
return;
}
@@ -293,7 +293,7 @@ export default defineComponent({
this.orangeLight = false;
this.redBottomLight = false;
if (status == Status.Data.Initialized) {
if (status == Status.Data.Initialized || status == Status.Data.Offline) {
this.redTopLight = true;
}
+15
View File
@@ -59,6 +59,21 @@ export default defineComponent({
'store.region.id': {
handler(regionId) {
this.selectedItemIndex = this.regionList.findIndex((reg) => reg.id == regionId);
console.log('region id', regionId);
}
},
'$route.query.region': {
immediate: true,
handler(regionQuery: string) {
if (regionQuery) {
this.store.region.id =
regionsJSON.find(
(reg) =>
reg.id == regionQuery.toLocaleLowerCase() ||
reg.value.toLocaleLowerCase() == regionQuery.toLocaleLowerCase()
)?.id || 'eu';
}
}
}
},
+3 -7
View File
@@ -279,7 +279,7 @@
</table>
</div>
<Loading v-if="!isDataLoaded && stations.length == 0" />
<Loading v-if="apiStore.dataStatuses.sceneries == Status.Loading" />
<div class="no-stations" v-else-if="stations.length == 0">
{{ $t('sceneries.no-stations') }}
@@ -288,7 +288,7 @@
</template>
<script lang="ts">
import { defineComponent, computed, PropType } from 'vue';
import { defineComponent, PropType } from 'vue';
import dateMixin from '../../mixins/dateMixin';
import stationInfoMixin from '../../mixins/stationInfoMixin';
import styleMixin from '../../mixins/styleMixin';
@@ -330,12 +330,8 @@ export default defineComponent({
const apiStore = useApiStore();
const stationFiltersStore = useStationFiltersStore();
const isDataLoaded = computed(() => {
return apiStore.dataStatuses.sceneries != Status.Data.Loading;
});
return {
isDataLoaded,
Status: Status.Data,
stationFiltersStore,
mainStore,
apiStore
+5 -6
View File
@@ -5,13 +5,12 @@
{{ $t('app.offline') }}
</div>
<Loading v-else-if="trains.length == 0 && apiStore.dataStatuses.trains == 0" key="loading" />
<Loading
v-else-if="trains.length == 0 && apiStore.dataStatuses.connection == 0"
key="loading"
/>
<div
class="table-info"
key="no-trains"
v-else-if="trains.length == 0 && apiStore.dataStatuses.trains != 0"
>
<div class="table-info" key="no-trains" v-else-if="trains.length == 0">
{{ $t('trains.no-trains') }}
</div>
+10 -3
View File
@@ -18,7 +18,8 @@ const routes: Array<RouteRecordRaw> = [
props: (route) => ({
train: route.query.train,
driver: route.query.driver,
trainId: route.query.trainId
trainId: route.query.trainId,
region: route.query.region
})
},
{
@@ -37,12 +38,18 @@ const routes: Array<RouteRecordRaw> = [
{
path: '/journal/timetables',
name: 'JournalTimetables',
component: JournalTimetablesVue
component: JournalTimetablesVue,
props: (route) => ({
region: route.query.region
})
},
{
path: '/journal/dispatchers',
name: 'JournalDispatchers',
component: JournalDispatchersVue
component: JournalDispatchersVue,
props: (route) => ({
region: route.query.region
})
},
{
path: '/:catchAll(.*)',
+39 -19
View File
@@ -18,7 +18,9 @@ export const useApiStore = defineStore('apiStore', {
activeData: undefined as API.ActiveData.Response | undefined,
rollingStockData: undefined as API.RollingStock.Response | undefined,
donatorsData: [] as API.Donators.Response,
sceneryData: [] as StationJSONData[]
sceneryData: [] as StationJSONData[],
activeDataTimeout: undefined as number | undefined
}),
actions: {
@@ -28,22 +30,32 @@ export const useApiStore = defineStore('apiStore', {
this.fetchDonatorsData();
this.fetchStationsGeneralInfo();
this.scheduleFetchActiveData();
if (this.activeDataTimeout === undefined) this.startActiveDataScheduler();
},
async setDataStatuses() {
if (!this.activeData?.activeSceneries) {
this.dataStatuses.sceneries = Status.Data.Error;
this.dataStatuses.trains = Status.Data.Error;
this.dataStatuses.dispatchers = Status.Data.Error;
// async setDataStatuses() {
// if (!window.navigator.onLine) {
// this.dataStatuses.connection = Status.Data.Offline;
// this.dataStatuses.sceneries = Status.Data.Offline;
// this.dataStatuses.trains = Status.Data.Offline;
// this.dataStatuses.dispatchers = Status.Data.Offline;
// this.dataStatuses.timetables = Status.Data.Offline;
// }
return;
}
// if (!this.activeData?.activeSceneries) {
// this.dataStatuses.connection = Status.Data.Loaded;
// this.dataStatuses.sceneries = Status.Data.Error;
// this.dataStatuses.trains = Status.Data.Error;
// this.dataStatuses.dispatchers = Status.Data.Error;
this.dataStatuses.sceneries = Status.Data.Loaded;
this.dataStatuses.trains = !this.activeData.trains ? Status.Data.Warning : Status.Data.Loaded;
this.dataStatuses.dispatchers = Status.Data.Loaded;
},
// return;
// }
// this.dataStatuses.connection = Status.Data.Loaded;
// this.dataStatuses.sceneries = Status.Data.Loaded;
// this.dataStatuses.trains = !this.activeData.trains ? Status.Data.Warning : Status.Data.Loaded;
// this.dataStatuses.dispatchers = Status.Data.Loaded;
// },
async fetchDonatorsData() {
try {
@@ -67,12 +79,16 @@ export const useApiStore = defineStore('apiStore', {
}
},
async scheduleFetchActiveData() {
async startActiveDataScheduler() {
if (!window.navigator.onLine) {
this.dataStatuses.connection = Status.Data.Offline;
return;
}
if (import.meta.env.VITE_API_MODE === 'mock') {
const mockActiveData = await import('../data/mockActiveData.json');
this.dataStatuses.connection = Status.Data.Loaded;
this.activeData = mockActiveData;
this.setDataStatuses();
console.warn('Stacjownik działa w trybie mockowania danych z WS');
@@ -84,21 +100,24 @@ export const useApiStore = defineStore('apiStore', {
this.activeData = data;
this.dataStatuses.connection = Status.Data.Loaded;
this.setDataStatuses();
} catch (error) {
this.dataStatuses.connection = Status.Data.Error;
console.error('Wystąpił błąd podczas pobierania danych online z API!');
} finally {
setTimeout(
this.activeDataTimeout = window.setTimeout(
() => {
this.scheduleFetchActiveData();
this.startActiveDataScheduler();
},
~~(1000 * (Math.random() * (25 - 20) + 25))
);
}
},
async stopActiveDataScheduler() {
window.clearTimeout(this.activeDataTimeout);
this.activeDataTimeout = undefined;
},
async fetchStationsGeneralInfo() {
const sceneryData: StationJSONData[] = (await http.get<StationJSONData[]>('api/getSceneries'))
.data;
@@ -108,6 +127,7 @@ export const useApiStore = defineStore('apiStore', {
return;
}
this.dataStatuses.sceneries = Status.Data.Loaded;
this.sceneryData = sceneryData;
}
}
+2 -1
View File
@@ -5,6 +5,7 @@
overflow-y: auto;
height: 90vh;
min-height: 550px;
margin-top: 0.5em;
padding-right: 0.2em;
}
@@ -24,7 +25,7 @@
text-align: end;
padding: 0.25em;
margin: 0.5em 0;
margin-top: 0.5em;
}
.journal_warning {
+49
View File
@@ -0,0 +1,49 @@
@font-face {
font-family: 'Quicksand';
src:
url('/fonts/Quicksand-Bold.woff2') format('woff2'),
url('/fonts/Quicksand-Bold.woff') format('woff');
font-weight: bold;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Quicksand';
src:
url('/fonts/Quicksand-SemiBold.woff2') format('woff2'),
url('/fonts/Quicksand-SemiBold.woff') format('woff');
font-weight: 600;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Quicksand';
src:
url('/fonts/Quicksand-Medium.woff2') format('woff2'),
url('/fonts/Quicksand-Medium.woff') format('woff');
font-weight: 500;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Quicksand';
src:
url('/fonts/Quicksand-Regular.woff2') format('woff2'),
url('/fonts/Quicksand-Regular.woff') format('woff');
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Quicksand';
src:
url('/fonts/Quicksand-Light.woff2') format('woff2'),
url('/fonts/Quicksand-Light.woff') format('woff');
font-weight: 300;
font-style: normal;
font-display: swap;
}
+2
View File
@@ -1,3 +1,5 @@
@import 'fonts.scss';
:root {
--clr-primary: #ffc014;
--clr-secondary: #2f2f2f;
+1 -1
View File
@@ -11,7 +11,7 @@ export namespace Status {
}
export enum Data {
Offline = 2,
Offline = -2,
Initialized = -1,
Loading = 0,
Error = 1,
+4 -2
View File
@@ -6,20 +6,22 @@ export default defineConfig({
server: {
port: 5001
},
publicDir: 'public',
plugins: [
vue(),
VitePWA({
registerType: 'autoUpdate',
includeAssets: ['/images/*.png', '/fonts/*.woff', '/fonts/*.woff2'],
workbox: {
disableDevLogs: true,
globPatterns: ['**/*.{js,css,html,png,svg,jpg}'],
runtimeCaching: [
{
urlPattern: new RegExp('^https://stacjownik.spythere.pl/api/getSceneries', 'i'),
urlPattern: new RegExp('^https://stacjownik.spythere.eu/api/getSceneries', 'i'),
handler: 'NetworkFirst',
options: {
cacheName: 'sceneries-cache',
cacheableResponse: {
statuses: [0, 200]
}