mirror of
https://gitlab.dit.htwk-leipzig.de/htwk-software/htwkalender-pwa.git
synced 2025-07-16 17:48:51 +02:00
Merge branch '18-setup-default-page' into 'main'
Resolve "setup default page" Closes #18 See merge request htwk-software/htwkalender-pwa!13
This commit is contained in:
@ -26,7 +26,6 @@ import { VueQueryDevtools } from "@tanstack/vue-query-devtools";
|
|||||||
import settingsStore from "@/store/settingsStore.ts";
|
import settingsStore from "@/store/settingsStore.ts";
|
||||||
import { setTheme } from "@/helpers/theme.ts";
|
import { setTheme } from "@/helpers/theme.ts";
|
||||||
import { usePrimeVue } from "primevue/config";
|
import { usePrimeVue } from "primevue/config";
|
||||||
|
|
||||||
const primeVue = usePrimeVue();
|
const primeVue = usePrimeVue();
|
||||||
|
|
||||||
const disabledPages = [
|
const disabledPages = [
|
||||||
@ -56,15 +55,15 @@ const updateMobile = () => {
|
|||||||
updateMobile();
|
updateMobile();
|
||||||
window.addEventListener("resize", updateMobile);
|
window.addEventListener("resize", updateMobile);
|
||||||
|
|
||||||
const settings = settingsStore();
|
const settings = settingsStore;
|
||||||
const emit = defineEmits(["dark-mode-toggled"]);
|
const emit = defineEmits(["dark-mode-toggled"]);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// set theme matching browser preference
|
// set theme matching browser preference
|
||||||
settings.setDarkMode(window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches)
|
settings().setDarkMode(window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches)
|
||||||
setTheme(settings, primeVue, emit);
|
setTheme(settings, primeVue, emit);
|
||||||
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", (e) => {
|
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", (e) => {
|
||||||
settings.setDarkMode(e.matches)
|
settings().setDarkMode(e.matches)
|
||||||
setTheme(settings, primeVue, emit);
|
setTheme(settings, primeVue, emit);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -26,9 +26,9 @@ const primeVue = usePrimeVue();
|
|||||||
|
|
||||||
const emit = defineEmits(["dark-mode-toggled"]);
|
const emit = defineEmits(["dark-mode-toggled"]);
|
||||||
|
|
||||||
const store = settingsStore();
|
const store = settingsStore;
|
||||||
|
|
||||||
const isDark = computed(() => store.isDark);
|
const isDark = computed(() => store().isDark);
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
45
frontend/src/components/DefaultPageSwitcher.vue
Normal file
45
frontend/src/components/DefaultPageSwitcher.vue
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<!--
|
||||||
|
Calendar implementation for the HTWK Leipzig timetable. Evaluation and display of the individual dates in iCal format.
|
||||||
|
Copyright (C) 2024 HTWKalender support@htwkalender.de
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, ComputedRef, ref } from "vue";
|
||||||
|
import settingsStore from "../store/settingsStore.ts";
|
||||||
|
|
||||||
|
const pageOptions: ComputedRef<(string | {
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
})[]> = computed(() => [...settingsStore().getDefaultPageOptions()]);
|
||||||
|
|
||||||
|
const selectedPage = ref(settingsStore().defaultPage);
|
||||||
|
|
||||||
|
function updateDefaultPage(page: { label: string; value: string }) {
|
||||||
|
settingsStore().setDefaultPage(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDefaultPage(settingsStore().defaultPage);
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<Dropdown
|
||||||
|
v-model="selectedPage"
|
||||||
|
:options="pageOptions"
|
||||||
|
placeholder="Select a Page"
|
||||||
|
class="w-full md:w-14rem"
|
||||||
|
option-label="label"
|
||||||
|
@change="updateDefaultPage($event.value)"
|
||||||
|
></Dropdown>
|
||||||
|
</template>
|
@ -15,26 +15,21 @@
|
|||||||
//along with this program. If not, see <https://www.gnu.org/licenses/>.
|
//along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { Store } from "pinia";
|
|
||||||
import { PrimeVueChangeTheme } from "primevue/config";
|
import { PrimeVueChangeTheme } from "primevue/config";
|
||||||
import { EmitFn } from "primevue/ts-helpers";
|
import { EmitFn } from "primevue/ts-helpers";
|
||||||
import { RemovableRef } from "@vueuse/core";
|
import settingsStore from "@/store/settingsStore.ts";
|
||||||
|
|
||||||
const darkTheme = ref("lara-dark-blue"),
|
const darkTheme = ref("lara-dark-blue"),
|
||||||
lightTheme = ref("lara-light-blue");
|
lightTheme = ref("lara-light-blue");
|
||||||
|
|
||||||
type SettingsStore = Store<"settingsStore", { locale: RemovableRef<string>, isDark: boolean }, NonNullable<unknown>, {
|
export type SettingsStore = typeof settingsStore;
|
||||||
setLocale(locale: string): void,
|
|
||||||
setDarkMode(isDark: boolean): void,
|
|
||||||
getDarkMode(): boolean
|
|
||||||
}>;
|
|
||||||
|
|
||||||
export function toggleTheme(
|
export function toggleTheme(
|
||||||
store: SettingsStore,
|
store: SettingsStore,
|
||||||
primeVue: { changeTheme: PrimeVueChangeTheme },
|
primeVue: { changeTheme: PrimeVueChangeTheme },
|
||||||
emit: EmitFn<"dark-mode-toggled"[]>,
|
emit: EmitFn<"dark-mode-toggled"[]>,
|
||||||
): void {
|
): void {
|
||||||
store.setDarkMode(!store.isDark);
|
store().setDarkMode(!store().isDark);
|
||||||
setTheme(store, primeVue, emit);
|
setTheme(store, primeVue, emit);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +38,7 @@ export function setTheme(
|
|||||||
{ changeTheme }: { changeTheme: PrimeVueChangeTheme },
|
{ changeTheme }: { changeTheme: PrimeVueChangeTheme },
|
||||||
emit: EmitFn<"dark-mode-toggled"[]>
|
emit: EmitFn<"dark-mode-toggled"[]>
|
||||||
) {
|
) {
|
||||||
const isDark = ref(store.isDark);
|
const isDark = ref(store().isDark);
|
||||||
const newTheme = isDark.value ? darkTheme.value : lightTheme.value,
|
const newTheme = isDark.value ? darkTheme.value : lightTheme.value,
|
||||||
oldTheme = isDark.value ? lightTheme.value : darkTheme.value;
|
oldTheme = isDark.value ? lightTheme.value : darkTheme.value;
|
||||||
changeTheme(oldTheme, newTheme, "theme-link", () => { });
|
changeTheme(oldTheme, newTheme, "theme-link", () => { });
|
||||||
|
@ -11,6 +11,10 @@
|
|||||||
"english": "Englisch",
|
"english": "Englisch",
|
||||||
"german": "Deutsch",
|
"german": "Deutsch",
|
||||||
"japanese": "Japanisch",
|
"japanese": "Japanisch",
|
||||||
|
"notFound": {
|
||||||
|
"headline": "404",
|
||||||
|
"subTitle": "Seite nicht gefunden"
|
||||||
|
},
|
||||||
"courseSelection": {
|
"courseSelection": {
|
||||||
"headline": "Willkommen beim HTWKalender",
|
"headline": "Willkommen beim HTWKalender",
|
||||||
"winterSemester": "Wintersemester",
|
"winterSemester": "Wintersemester",
|
||||||
@ -254,6 +258,7 @@
|
|||||||
"headline": "Einstellungen",
|
"headline": "Einstellungen",
|
||||||
"subTitle": "Hier kannst du deine Einstellungen bearbeiten.",
|
"subTitle": "Hier kannst du deine Einstellungen bearbeiten.",
|
||||||
"language": "Sprache einstellen",
|
"language": "Sprache einstellen",
|
||||||
"darkMode": "Design auswählen"
|
"darkMode": "Design auswählen",
|
||||||
|
"defaultPage": "Standardseite"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,10 @@
|
|||||||
"english": "English",
|
"english": "English",
|
||||||
"german": "German",
|
"german": "German",
|
||||||
"japanese": "Japanese",
|
"japanese": "Japanese",
|
||||||
|
"notFound": {
|
||||||
|
"headline": "404",
|
||||||
|
"subTitle": "page not found"
|
||||||
|
},
|
||||||
"courseSelection": {
|
"courseSelection": {
|
||||||
"headline": "welcome to HTWKalender",
|
"headline": "welcome to HTWKalender",
|
||||||
"winterSemester": "winter semester",
|
"winterSemester": "winter semester",
|
||||||
@ -254,6 +258,7 @@
|
|||||||
"headline": "Settings",
|
"headline": "Settings",
|
||||||
"subTitle": "Here you can change your settings.",
|
"subTitle": "Here you can change your settings.",
|
||||||
"language": "Choose your language",
|
"language": "Choose your language",
|
||||||
"darkMode": "Switch page theme"
|
"darkMode": "Switch page theme",
|
||||||
|
"defaultPage": "Default page"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,10 @@
|
|||||||
"english": "英語",
|
"english": "英語",
|
||||||
"german": "ドイツ語",
|
"german": "ドイツ語",
|
||||||
"japanese": "日本語",
|
"japanese": "日本語",
|
||||||
|
"notFound": {
|
||||||
|
"headline": "404",
|
||||||
|
"subTitle": "ページが見つかりません"
|
||||||
|
},
|
||||||
"courseSelection": {
|
"courseSelection": {
|
||||||
"headline": "HTWカレンダーへようこそ",
|
"headline": "HTWカレンダーへようこそ",
|
||||||
"winterSemester": "冬学期",
|
"winterSemester": "冬学期",
|
||||||
@ -254,6 +258,7 @@
|
|||||||
"headline": "設定",
|
"headline": "設定",
|
||||||
"subTitle": "ここで設定を編集できます。",
|
"subTitle": "ここで設定を編集できます。",
|
||||||
"language": "言語",
|
"language": "言語",
|
||||||
"darkMode": "ダークモード"
|
"darkMode": "ダークモード",
|
||||||
|
"defaultPage": "デフォルトページ"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,14 +30,22 @@ const CourseSelection = () => import("../view/CourseSelection.vue");
|
|||||||
const FreeRooms = () => import("../view/FreeRooms.vue");
|
const FreeRooms = () => import("../view/FreeRooms.vue");
|
||||||
const CalenderViewer = () => import("../view/UserCalendar.vue");
|
const CalenderViewer = () => import("../view/UserCalendar.vue");
|
||||||
const SettingsView = () => import("../view/SettingsView.vue");
|
const SettingsView = () => import("../view/SettingsView.vue");
|
||||||
|
const NotFound = () => import("../view/NotFound.vue");
|
||||||
|
|
||||||
import i18n from "../i18n";
|
import i18n from "../i18n";
|
||||||
|
import settingsStore from "@/store/settingsStore.ts";
|
||||||
|
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory(import.meta.env.BASE_URL),
|
history: createWebHistory(import.meta.env.BASE_URL),
|
||||||
routes: [
|
routes: [
|
||||||
{
|
{
|
||||||
path: "/",
|
path: "/",
|
||||||
|
name: "default",
|
||||||
|
component: CourseSelection,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/home",
|
||||||
name: "home",
|
name: "home",
|
||||||
component: CourseSelection,
|
component: CourseSelection,
|
||||||
},
|
},
|
||||||
@ -123,18 +131,31 @@ const router = createRouter({
|
|||||||
path: "/settings",
|
path: "/settings",
|
||||||
name: "settings",
|
name: "settings",
|
||||||
component: SettingsView,
|
component: SettingsView,
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
path: "/:catchAll(.*)", // Catch all undefined routes
|
||||||
|
name: "not-found",
|
||||||
|
component: NotFound, // Replace with your NotFound component
|
||||||
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
router.beforeEach(async (to, from) => {
|
router.beforeEach(async (to, from, next) => {
|
||||||
const newLocale = to.params.locale;
|
const newLocale = to.params.locale;
|
||||||
const prevLocale = from.params.locale;
|
const prevLocale = from.params.locale;
|
||||||
// If the locale hasn't changed, do nothing
|
// If the locale hasn't changed, do nothing
|
||||||
if (newLocale === prevLocale) {
|
if (!(newLocale === prevLocale)) {
|
||||||
return;
|
i18n.setLocale(newLocale);
|
||||||
|
}
|
||||||
|
|
||||||
|
const userSettings = settingsStore();
|
||||||
|
const defaultPath = userSettings.defaultPage || "/home";
|
||||||
|
|
||||||
|
if (to.path === "/") {
|
||||||
|
next(defaultPath.value);
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
}
|
}
|
||||||
i18n.setLocale(newLocale);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
@ -16,12 +16,14 @@
|
|||||||
|
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { useLocalStorage } from "@vueuse/core";
|
import { useLocalStorage } from "@vueuse/core";
|
||||||
|
import router from "@/router";
|
||||||
|
|
||||||
const settingsStore = defineStore("settingsStore", {
|
const settingsStore = defineStore("settingsStore", {
|
||||||
state: () => {
|
state: () => {
|
||||||
return {
|
return {
|
||||||
locale: useLocalStorage("locale", "en"), //useLocalStorage takes in a key of 'count' and default value of 0
|
locale: useLocalStorage("locale", "en"), //useLocalStorage takes in a key of 'count' and default value of 0
|
||||||
isDark: true,
|
isDark: true,
|
||||||
|
defaultPage: useLocalStorage("defaultPage", {label: "Home", value: "/home"}),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
@ -33,7 +35,34 @@ const settingsStore = defineStore("settingsStore", {
|
|||||||
},
|
},
|
||||||
getDarkMode(): boolean {
|
getDarkMode(): boolean {
|
||||||
return this.isDark;
|
return this.isDark;
|
||||||
}
|
},
|
||||||
|
setDefaultPage(page: {
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
}) {
|
||||||
|
this.defaultPage = page;
|
||||||
|
},
|
||||||
|
getDefaultPageOptions(): {
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
}[] {
|
||||||
|
// get a string array of all the route names
|
||||||
|
const options: {
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
}[] = [];
|
||||||
|
router.getRoutes().forEach((route) => {
|
||||||
|
if (route.name) {
|
||||||
|
if (typeof route.name === "string") {
|
||||||
|
options.push({
|
||||||
|
label: route.name,
|
||||||
|
value: route.path,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return options;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
16
frontend/src/view/NotFound.vue
Normal file
16
frontend/src/view/NotFound.vue
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import DynamicPage from "@/view/DynamicPage.vue";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<DynamicPage
|
||||||
|
hide-content
|
||||||
|
:headline="$t('notFound.headline')"
|
||||||
|
:sub-title="$t('notFound.subTitle')"
|
||||||
|
>
|
||||||
|
</DynamicPage>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -3,6 +3,7 @@
|
|||||||
import LocaleSwitcher from "@/components/LocaleSwitcher.vue";
|
import LocaleSwitcher from "@/components/LocaleSwitcher.vue";
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import DarkModeSwitcher from "@/components/DarkModeSwitcher.vue";
|
import DarkModeSwitcher from "@/components/DarkModeSwitcher.vue";
|
||||||
|
import DefaultPageSwitcher from "@/components/DefaultPageSwitcher.vue";
|
||||||
|
|
||||||
const icon = "pi pi-cog";
|
const icon = "pi pi-cog";
|
||||||
const isDark = ref(true);
|
const isDark = ref(true);
|
||||||
@ -44,6 +45,14 @@ class="opacity-100 transition-all transition-duration-500 transition-ease-in-out
|
|||||||
<LocaleSwitcher />
|
<LocaleSwitcher />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="grid my-2">
|
||||||
|
<div class="col text-center">
|
||||||
|
{{ $t("settings.defaultPage") }}
|
||||||
|
</div>
|
||||||
|
<div class="col text-center">
|
||||||
|
<DefaultPageSwitcher />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="grid my-2">
|
<div class="grid my-2">
|
||||||
<div class="col text-center">
|
<div class="col text-center">
|
||||||
{{ $t("settings.darkMode") }}
|
{{ $t("settings.darkMode") }}
|
||||||
|
Reference in New Issue
Block a user