diff --git a/frontend/src/App.vue b/frontend/src/App.vue index ff32417..c617135 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -26,7 +26,6 @@ import { VueQueryDevtools } from "@tanstack/vue-query-devtools"; import settingsStore from "@/store/settingsStore.ts"; import { setTheme } from "@/helpers/theme.ts"; import { usePrimeVue } from "primevue/config"; - const primeVue = usePrimeVue(); const disabledPages = [ @@ -56,15 +55,15 @@ const updateMobile = () => { updateMobile(); window.addEventListener("resize", updateMobile); -const settings = settingsStore(); +const settings = settingsStore; const emit = defineEmits(["dark-mode-toggled"]); onMounted(() => { // 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); window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", (e) => { - settings.setDarkMode(e.matches) + settings().setDarkMode(e.matches) setTheme(settings, primeVue, emit); }); }); diff --git a/frontend/src/components/DarkModeSwitcher.vue b/frontend/src/components/DarkModeSwitcher.vue index 452825e..cba77f8 100644 --- a/frontend/src/components/DarkModeSwitcher.vue +++ b/frontend/src/components/DarkModeSwitcher.vue @@ -26,9 +26,9 @@ const primeVue = usePrimeVue(); const emit = defineEmits(["dark-mode-toggled"]); -const store = settingsStore(); +const store = settingsStore; -const isDark = computed(() => store.isDark); +const isDark = computed(() => store().isDark); diff --git a/frontend/src/components/DefaultPageSwitcher.vue b/frontend/src/components/DefaultPageSwitcher.vue new file mode 100644 index 0000000..8e44937 --- /dev/null +++ b/frontend/src/components/DefaultPageSwitcher.vue @@ -0,0 +1,45 @@ + + + + diff --git a/frontend/src/helpers/theme.ts b/frontend/src/helpers/theme.ts index 43b0c8f..07f5643 100644 --- a/frontend/src/helpers/theme.ts +++ b/frontend/src/helpers/theme.ts @@ -15,26 +15,21 @@ //along with this program. If not, see . import { ref } from "vue"; -import { Store } from "pinia"; import { PrimeVueChangeTheme } from "primevue/config"; import { EmitFn } from "primevue/ts-helpers"; -import { RemovableRef } from "@vueuse/core"; +import settingsStore from "@/store/settingsStore.ts"; const darkTheme = ref("lara-dark-blue"), lightTheme = ref("lara-light-blue"); -type SettingsStore = Store<"settingsStore", { locale: RemovableRef, isDark: boolean }, NonNullable, { - setLocale(locale: string): void, - setDarkMode(isDark: boolean): void, - getDarkMode(): boolean -}>; +export type SettingsStore = typeof settingsStore; export function toggleTheme( store: SettingsStore, primeVue: { changeTheme: PrimeVueChangeTheme }, emit: EmitFn<"dark-mode-toggled"[]>, ): void { - store.setDarkMode(!store.isDark); + store().setDarkMode(!store().isDark); setTheme(store, primeVue, emit); } @@ -43,7 +38,7 @@ export function setTheme( { changeTheme }: { changeTheme: PrimeVueChangeTheme }, emit: EmitFn<"dark-mode-toggled"[]> ) { - const isDark = ref(store.isDark); + const isDark = ref(store().isDark); const newTheme = isDark.value ? darkTheme.value : lightTheme.value, oldTheme = isDark.value ? lightTheme.value : darkTheme.value; changeTheme(oldTheme, newTheme, "theme-link", () => { }); diff --git a/frontend/src/i18n/translations/de.json b/frontend/src/i18n/translations/de.json index 70af13d..806504f 100644 --- a/frontend/src/i18n/translations/de.json +++ b/frontend/src/i18n/translations/de.json @@ -11,6 +11,10 @@ "english": "Englisch", "german": "Deutsch", "japanese": "Japanisch", + "notFound": { + "headline": "404", + "subTitle": "Seite nicht gefunden" + }, "courseSelection": { "headline": "Willkommen beim HTWKalender", "winterSemester": "Wintersemester", @@ -254,6 +258,7 @@ "headline": "Einstellungen", "subTitle": "Hier kannst du deine Einstellungen bearbeiten.", "language": "Sprache einstellen", - "darkMode": "Design auswählen" + "darkMode": "Design auswählen", + "defaultPage": "Standardseite" } } diff --git a/frontend/src/i18n/translations/en.json b/frontend/src/i18n/translations/en.json index 5db0af9..5a22d8c 100644 --- a/frontend/src/i18n/translations/en.json +++ b/frontend/src/i18n/translations/en.json @@ -11,6 +11,10 @@ "english": "English", "german": "German", "japanese": "Japanese", + "notFound": { + "headline": "404", + "subTitle": "page not found" + }, "courseSelection": { "headline": "welcome to HTWKalender", "winterSemester": "winter semester", @@ -254,6 +258,7 @@ "headline": "Settings", "subTitle": "Here you can change your settings.", "language": "Choose your language", - "darkMode": "Switch page theme" + "darkMode": "Switch page theme", + "defaultPage": "Default page" } } diff --git a/frontend/src/i18n/translations/ja.json b/frontend/src/i18n/translations/ja.json index b223c11..ffd1870 100644 --- a/frontend/src/i18n/translations/ja.json +++ b/frontend/src/i18n/translations/ja.json @@ -11,6 +11,10 @@ "english": "英語", "german": "ドイツ語", "japanese": "日本語", + "notFound": { + "headline": "404", + "subTitle": "ページが見つかりません" + }, "courseSelection": { "headline": "HTWカレンダーへようこそ", "winterSemester": "冬学期", @@ -254,6 +258,7 @@ "headline": "設定", "subTitle": "ここで設定を編集できます。", "language": "言語", - "darkMode": "ダークモード" + "darkMode": "ダークモード", + "defaultPage": "デフォルトページ" } } diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts index 3c6c214..5412600 100644 --- a/frontend/src/router/index.ts +++ b/frontend/src/router/index.ts @@ -30,14 +30,22 @@ const CourseSelection = () => import("../view/CourseSelection.vue"); const FreeRooms = () => import("../view/FreeRooms.vue"); const CalenderViewer = () => import("../view/UserCalendar.vue"); const SettingsView = () => import("../view/SettingsView.vue"); +const NotFound = () => import("../view/NotFound.vue"); import i18n from "../i18n"; +import settingsStore from "@/store/settingsStore.ts"; + const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: [ { path: "/", + name: "default", + component: CourseSelection, + }, + { + path: "/home", name: "home", component: CourseSelection, }, @@ -123,18 +131,31 @@ const router = createRouter({ path: "/settings", name: "settings", 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 prevLocale = from.params.locale; // If the locale hasn't changed, do nothing - if (newLocale === prevLocale) { - return; + if (!(newLocale === prevLocale)) { + 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; diff --git a/frontend/src/store/settingsStore.ts b/frontend/src/store/settingsStore.ts index 55021be..5551c95 100644 --- a/frontend/src/store/settingsStore.ts +++ b/frontend/src/store/settingsStore.ts @@ -16,12 +16,14 @@ import { defineStore } from "pinia"; import { useLocalStorage } from "@vueuse/core"; +import router from "@/router"; const settingsStore = defineStore("settingsStore", { state: () => { return { locale: useLocalStorage("locale", "en"), //useLocalStorage takes in a key of 'count' and default value of 0 isDark: true, + defaultPage: useLocalStorage("defaultPage", {label: "Home", value: "/home"}), }; }, actions: { @@ -33,8 +35,35 @@ const settingsStore = defineStore("settingsStore", { }, getDarkMode(): boolean { 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; + }, }, }); -export default settingsStore; +export default settingsStore; \ No newline at end of file diff --git a/frontend/src/view/NotFound.vue b/frontend/src/view/NotFound.vue new file mode 100644 index 0000000..8e215cc --- /dev/null +++ b/frontend/src/view/NotFound.vue @@ -0,0 +1,16 @@ + + + + + \ No newline at end of file diff --git a/frontend/src/view/SettingsView.vue b/frontend/src/view/SettingsView.vue index b52550f..65a3cb4 100644 --- a/frontend/src/view/SettingsView.vue +++ b/frontend/src/view/SettingsView.vue @@ -3,6 +3,7 @@ import LocaleSwitcher from "@/components/LocaleSwitcher.vue"; import { ref } from "vue"; import DarkModeSwitcher from "@/components/DarkModeSwitcher.vue"; +import DefaultPageSwitcher from "@/components/DefaultPageSwitcher.vue"; const icon = "pi pi-cog"; const isDark = ref(true); @@ -44,6 +45,14 @@ class="opacity-100 transition-all transition-duration-500 transition-ease-in-out +
+
+ {{ $t("settings.defaultPage") }} +
+
+ +
+
{{ $t("settings.darkMode") }}