Merge branch 'development' into 'main'

Development

See merge request htwk-software/htwkalender!49
This commit is contained in:
Elmar Kresse
2024-07-03 21:27:18 +00:00
37 changed files with 1009 additions and 256 deletions

1
frontend/.gitignore vendored
View File

@ -10,6 +10,7 @@ lerna-debug.log*
node_modules
dist
dist-ssr
.vite-ssg-temp
*.local
# Editor directories and files

View File

@ -1,5 +1,5 @@
<!doctype html>
<html lang="en">
<html lang="de">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" sizes="32x32" />
@ -12,10 +12,9 @@
href="/themes/lara-light-blue/theme.css"
/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>HTWKalender</title>
</head>
<body>
<div id="app"></div>
<div id="app"><!--app-html--></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

View File

@ -50,7 +50,7 @@ http {
index index.html index.htm;
#necessary to display vue subpage
try_files $uri $uri/ /index.html;
try_files $uri $uri.html $uri/ /index.html;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,7 @@
"type": "module",
"scripts": {
"dev": "vite",
"build": "vue-tsc && vite build",
"build": "vue-tsc && vite-ssg build",
"preview": "vite preview",
"lint": "eslint --ext .js,.vue --ignore-path .gitignore --fix src",
"lint-no-fix": "eslint --ext .js,.vue --ignore-path .gitignore src",
@ -20,6 +20,7 @@
"@fullcalendar/vue3": "^6.1.11",
"@tanstack/vue-query": "^5.28.9",
"@tanstack/vue-query-devtools": "^5.28.10",
"@unhead/ssr": "^1.9.14",
"@unhead/vue": "^1.9.10",
"@vueuse/core": "^10.9.0",
"pinia": "^2.1.7",
@ -27,6 +28,7 @@
"primeicons": "^6.0.1",
"primevue": "^3.50.0",
"source-sans": "^3.46.0",
"vite-ssg": "^0.23.7",
"vue": "^3.4.11",
"vue-i18n": "^9.10.2",
"vue-router": "^4.3.0"
@ -46,6 +48,7 @@
"terser": "^5.31.0",
"typescript": "^5.4.3",
"vite": "^5.2.7",
"vite-ssg-sitemap": "^0.7.1",
"vitest": "^1.4.0",
"vue-tsc": "^1.8.27"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

@ -1,2 +0,0 @@
User-agent: *
Allow: /

View File

@ -19,7 +19,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
<script lang="ts" setup>
import MenuBar from "./components/MenuBar.vue";
import { RouteRecordName, RouterView, useRoute, useRouter } from "vue-router";
import { useHead } from "@unhead/vue";
import { useHead, useServerHead, useServerSeoMeta } from "@unhead/vue";
import CalendarPreview from "./components/CalendarPreview.vue";
import moduleStore from "./store/moduleStore.ts";
import { computed, provide, ref } from "vue";
@ -42,12 +42,19 @@ const disabledPages = [
// Provide canonical link for SEO
const router = useRouter();
const route = useRoute();
const baseUri = "https://cal.htwk-leipzig.de"; // could be stored in .env
const domain = "cal.htwk-leipzig.de"
provide('domain', domain);
const baseUri = "https://" + domain;
const canonical = computed(() => `${baseUri}${router.resolve(route.name ? { name: route.name } : route).path}`);
const title = computed(() => route.meta.label?
`HTWKalender - ${t(String(route.meta.label))}`:
"HTWKalender"
);
const description = computed(() => route.meta.description?
t(String(route.meta.description)):
t("description")
);
useHead({
title: title,
@ -55,17 +62,33 @@ useHead({
{ rel: "canonical", href: canonical},
],
meta: [
{
name: "description",
content: "Dein individueller Stundenplan mit Sportevents und Prüfungen. Finde kommende Veranstaltungen oder freie Räume zum Lernen und Arbeiten.",
},
{
name: "keywords",
content: "HTWK Leipzig, Stundenplan, iCal, freie Räume, Lerngruppen, Sport, Prüfungen",
}
{ name: "description", content: description},
{ property: "og:description", content: description},
]
});
// SEO optimization
useServerHead({
title: title
});
useServerSeoMeta(
{
title: title,
description: description,
keywords: "HTWK Leipzig, Stundenplan, iCal, freie Räume, Lerngruppen, Sport, Prüfungen",
// openGraph
ogTitle: title,
ogDescription: description,
ogImage: `${baseUri}/img/banner-image.png`,
ogImageType: "image/png",
ogLocale: "de_DE",
ogUrl: canonical,
// twitter
twitterCard: "summary_large_image",
twitterSite: "@HTWKLeipzig",
}
);
const store = moduleStore();
const mobilePage = ref(true);
provide("mobilePage", mobilePage);
@ -75,12 +98,14 @@ const isDisabled = (routeName: RouteRecordName | null | undefined) => {
};
const updateMobile = () => {
if (import.meta.env.SSR) return;
mobilePage.value = window.innerWidth <= 992;
};
updateMobile();
window.addEventListener("resize", updateMobile);
if (!import.meta.env.SSR)
window.addEventListener("resize", updateMobile);
</script>
<template>

View File

@ -17,6 +17,9 @@
import { Module } from "../model/module.ts";
export async function createIndividualFeed(modules: Module[]): Promise<string> {
if (import.meta.env.SSR) {
return "";
}
try {
const response = await fetch("/api/feed", {
method: "POST",
@ -62,6 +65,9 @@ export async function saveIndividualFeed(
token: string,
modules: Module[],
): Promise<string> {
if (import.meta.env.SSR) {
return "";
}
await fetch("/api/collections/feeds/records/" + token, {
method: "PATCH",
headers: {
@ -81,6 +87,9 @@ export async function saveIndividualFeed(
}
export async function deleteIndividualFeed(token: string): Promise<void> {
if (import.meta.env.SSR) {
return;
}
await fetch("/api/feed?token=" + token, {
method: "DELETE",
})

View File

@ -19,6 +19,9 @@
import { Module } from "../model/module.ts";
export async function fetchCourse(): Promise<string[]> {
if (import.meta.env.SSR) {
return [];
}
const courses: string[] = [];
await fetch("/api/courses")
.then((response) => {
@ -39,6 +42,9 @@ export async function fetchCourse(): Promise<string[]> {
export async function fetchCourseBySemester(
semester: string,
): Promise<string[]> {
if (import.meta.env.SSR) {
return [];
}
const courses: string[] = [];
await fetch("/api/courses/events?semester=" + semester)
.then((response) => {
@ -60,6 +66,9 @@ export async function fetchModulesByCourseAndSemester(
course: string,
semester: string,
): Promise<Module[]> {
if (import.meta.env.SSR) {
return [];
}
const modules: Module[] = [];
await fetch("/api/course/modules?course=" + course + "&semester=" + semester)
.then((response) => {
@ -86,6 +95,9 @@ export async function fetchModulesByCourseAndSemester(
}
export async function fetchAllModules(): Promise<Module[]> {
if (import.meta.env.SSR) {
return [];
}
const modules: Module[] = [];
await fetch("/api/modules")
.then((response) => {

View File

@ -17,6 +17,9 @@
// function to fetch course data from the API
export async function fetchEventTypes(): Promise<string[]> {
if (import.meta.env.SSR) {
return [];
}
const eventTypes: string[] = [];
await fetch("/api/events/types")
.then((response) => {
@ -30,4 +33,4 @@ export async function fetchEventTypes(): Promise<string[]> {
});
});
return eventTypes;
}
}

View File

@ -17,6 +17,9 @@
import { Module } from "../model/module";
export async function fetchModule(module: Module): Promise<Module> {
if (import.meta.env.SSR) {
return new Module("", "", "", "", "", "", "", false, []);
}
// request to the data-manager on /api/module with query parameters name as the module name
const request = new Request("/api/module?uuid=" + module.uuid);

View File

@ -17,6 +17,9 @@
import { AnonymizedEventDTO } from "../model/event.ts";
export async function fetchRoom(): Promise<string[]> {
if (import.meta.env.SSR) {
return [];
}
const rooms: string[] = [];
await fetch("/api/rooms")
.then((response) => {
@ -33,6 +36,9 @@ export async function fetchEventsByRoomAndDuration(
from_date: string,
to_date: string,
): Promise<AnonymizedEventDTO[]> {
if (import.meta.env.SSR) {
return [];
}
const events: AnonymizedEventDTO[] = [];
await fetch(
"/api/schedule?room=" + room + "&from=" + from_date + "&to=" + to_date,

View File

@ -18,6 +18,9 @@ import { Module } from "../model/module";
import { Calendar } from "../model/calendar";
export async function getCalender(token: string): Promise<Module[]> {
if (import.meta.env.SSR) {
return [];
}
const request = new Request("/api/collections/feeds/records/" + token, {
method: "GET",
});

View File

@ -19,6 +19,9 @@ export async function requestFreeRooms(
from: string,
to: string,
): Promise<string[]> {
if (import.meta.env.SSR) {
return [];
}
const rooms: string[] = [];
await fetch("/api/rooms/free?from=" + from + "&to=" + to)
.then((response) => {

View File

@ -27,7 +27,7 @@ import {
DataTableRowUnselectEvent,
} from "primevue/datatable";
import { useDialog } from "primevue/usedialog";
import router from "../router";
import { router } from "@/main";
import { fetchModule } from "../api/fetchModule.ts";
import { useI18n } from "vue-i18n";
import { fetchEventTypes } from "../api/fetchEvents.ts";

View File

@ -24,7 +24,7 @@ const PrimeVue = usePrimeVue();
const emit = defineEmits(["dark-mode-toggled"]);
const isDark = ref(true);
const isDark = ref(false);
const darkTheme = ref("lara-dark-blue"),
lightTheme = ref("lara-light-blue");

View File

@ -26,7 +26,7 @@ import { CalendarOptions, DatesSetArg, EventInput } from "@fullcalendar/core";
import { fetchEventsByRoomAndDuration } from "../api/fetchRoom.ts";
import { useI18n } from "vue-i18n";
import allLocales from "@fullcalendar/core/locales-all";
import router from "@/router";
import { router } from "@/main";
import { formatYearMonthDay } from "@/helpers/dates";
import { useQuery } from "@tanstack/vue-query";
import { watch } from "vue";

View File

@ -27,7 +27,7 @@ function setup() {
_i18n = createI18n({
legacy: false,
locale: localeStore().locale,
fallbackLocale: "en",
fallbackLocale: "de",
messages: {
en,
de,

View File

@ -6,6 +6,7 @@
"faq": "FAQ",
"imprint": "Impressum",
"privacy": "Datenschutz",
"description": "Dein individueller Stundenplan mit Sportevents und Prüfungen. Finde kommende Veranstaltungen oder freie Räume zum Lernen und Arbeiten.",
"english": "Englisch",
"german": "Deutsch",
"courseSelection": {
@ -22,6 +23,7 @@
"roomSchedule": "Raumbelegung",
"headline": "Raumbelegung",
"detail": "Bitte wähle einen Raum aus, um die Belegung einzusehen",
"description": "Möchtest du schnell checken, ob ein Raum frei ist? Hier kannst du die Belegung der Räume an der HTWK Leipzig einsehen.",
"dropDownSelect": "Bitte wähle einen Raum aus",
"noRoomsAvailable": "Keine Räume verfügbar",
"available": "verfügbar",
@ -30,6 +32,7 @@
"freeRooms": {
"freeRooms": "Freie Räume",
"detail": "Bitte wähle einen Zeitraum aus, um alle Räume ohne Belegung anzuzeigen.",
"description": "Freier Lerngruppenraum gesucht? Hier kannst du alle freien Räume in einem bestimmten Zeitraum an der HTWK Leipzig einsehen.",
"searchByRoom": "Suche nach Räumen",
"pleaseSelectDate": "Bitte wähle ein Datum aus",
"room": "Raum",
@ -68,6 +71,7 @@
}
},
"editCalendarView": {
"description": "Mit deinem Token kannst du deinen HTWKalender jederzeit bearbeiten und sogar ins nächste Semester mitnehmen",
"error": "Fehler",
"invalidToken": "Ungültiger Token",
"headline": "Bearbeite deinen HTWKalender",
@ -147,6 +151,7 @@
},
"faqView": {
"headline": "Fragen und Antworten",
"description": "Falls du Fragen zum HTWKalender hast, findest du hier Antworten auf häufig gestellte Fragen und unsere Kontaktdaten.",
"firstQuestion": "Wie funktioniert das Kalender erstellen mit dem HTWKalender?",
"firstAnswer": "Die Webseite ermöglicht es deinen HTWK-Stundenplan in eines deiner bevorzugten Kalender-Verwaltungs-Programme (Outlook, Google Kalender, etc.) einzubinden. ",
"secondQuestion": "Wie genau funktioniert das alles?",

View File

@ -6,6 +6,7 @@
"faq": "faq",
"imprint": "imprint",
"privacy": "privacy",
"description": "Your individual timetable with sports events and exams. Find upcoming events or free rooms for studying and working.",
"english": "English",
"german": "German",
"courseSelection": {
@ -22,6 +23,7 @@
"roomSchedule": "room occupancy",
"headline": "room occupancy plan",
"detail": "Please select a room to view the occupancy.",
"description": "Would you like to quickly check whether a room is available? Here you can see the occupancy of the rooms at HTWK Leipzig.",
"dropDownSelect": "please select a room",
"noRoomsAvailable": "no rooms listed",
"available": "available",
@ -30,6 +32,7 @@
"freeRooms": {
"freeRooms": "free rooms",
"detail": "Please select a time period to display rooms that have no occupancy.",
"description": "Looking for a free study group room? Here you can see all available rooms at HTWK Leipzig in a specific period.",
"searchByRoom": "search by room",
"pleaseSelectDate": "please select a date",
"room": "room",
@ -68,6 +71,7 @@
}
},
"editCalendarView": {
"description": "With your token, you can edit your HTW calendar at any time and even take it with you into the next semester",
"error": "error",
"invalidToken": "invalid token",
"headline": "edit your HTWKalender",
@ -147,6 +151,7 @@
},
"faqView": {
"headline": "faq",
"description": "If you have any questions about the HTWKalender, you will find answers to frequently asked questions and our contact details here.",
"firstQuestion": "How does calendar creation work with HTWKalender?",
"firstAnswer": "The website allows you to integrate your HTWK timetable into one of your preferred calendar management programs (Outlook, Google Calendar, etc.).",
"secondQuestion": "How does it all work exactly?",

View File

@ -16,8 +16,7 @@
import "source-sans/source-sans-3.css";
import { createApp } from "vue";
import { createHead } from "@unhead/vue";
import { ViteSSG } from "vite-ssg";
import "./style.css";
import App from "./App.vue";
import PrimeVue from "primevue/config";
@ -36,7 +35,7 @@ import Slider from "primevue/slider";
import ToggleButton from "primevue/togglebutton";
import "primeicons/primeicons.css";
import "primeflex/primeflex.css";
import router from "./router";
import routes from "./router";
import SpeedDial from "primevue/speeddial";
import TabView from "primevue/tabview";
import TabPanel from "primevue/tabpanel";
@ -57,57 +56,89 @@ import Skeleton from "primevue/skeleton";
import Calendar from "primevue/calendar";
import i18n from "./i18n";
import { VueQueryPlugin } from "@tanstack/vue-query";
import { Router } from "vue-router";
const app = createApp(App);
const pinia = createPinia();
var router : Router;
app.use(VueQueryPlugin, {
queryClientConfig: {
defaultOptions: {
queries: {
refetchOnWindowFocus: false,
},
},
export const createApp = ViteSSG(
App,
{
base: import.meta.env.BASE_URL,
routes: routes.routes,
},
});
(ctx) => {
const { app } = ctx;
const pinia = createPinia();
app.use(pinia);
const head = createHead();
app.use(head);
router = ctx.router;
app.use(PrimeVue);
app.use(router);
app.use(ToastService);
app.use(pinia);
app.use(DialogService);
i18n.setup();
app.use(i18n.vueI18n);
app.component("Avatar", Avatar);
app.component("Badge", Badge);
app.component("Button", Button);
app.component("Menu", Menu);
app.component("Menubar", Menubar);
app.component("Dialog", Dialog);
app.component("Dropdown", Dropdown);
app.component("InputText", InputText);
app.component("InputSwitch", InputSwitch);
app.component("Card", Card);
app.component("DataView", DataView);
app.component("Slider", Slider);
app.component("ToggleButton", ToggleButton);
app.component("SpeedDial", SpeedDial);
app.component("TabView", TabView);
app.component("TabPanel", TabPanel);
app.component("MultiSelect", MultiSelect);
app.component("Tag", Tag);
app.component("Toast", Toast);
app.component("Accordion", Accordion);
app.component("AccordionTab", AccordionTab);
app.component("DataTable", DataTable);
app.component("Column", Column);
app.component("DynamicDialog", DynamicDialog);
app.component("ProgressSpinner", ProgressSpinner);
app.component("Checkbox", Checkbox);
app.component("Skeleton", Skeleton);
app.component("Calendar", Calendar);
router.beforeEach(async (to, from) => {
if (import.meta.env.SSR) {
return;
}
app.mount("#app");
// External redirect
if (to.matched.some((record) => record.meta.redirect)) {
window.location.replace(to.meta.redirect as string);
return;
}
const newLocale = to.params.locale;
const prevLocale = from.params.locale;
// If the locale hasn't changed, do nothing
if (newLocale === prevLocale) {
return;
}
i18n.setLocale(newLocale);
});
app.use(VueQueryPlugin, {
queryClientConfig: {
defaultOptions: {
queries: {
refetchOnWindowFocus: false,
},
},
},
});
app.use(router);
app.use(ToastService);
app.use(DialogService);
i18n.setup();
app.use(i18n.vueI18n);
app.use(PrimeVue);
app.component("Avatar", Avatar);
app.component("Badge", Badge);
app.component("Button", Button);
app.component("Menu", Menu);
app.component("Menubar", Menubar);
app.component("Dialog", Dialog);
app.component("Dropdown", Dropdown);
app.component("InputText", InputText);
app.component("InputSwitch", InputSwitch);
app.component("Card", Card);
app.component("DataView", DataView);
app.component("Slider", Slider);
app.component("ToggleButton", ToggleButton);
app.component("SpeedDial", SpeedDial);
app.component("TabView", TabView);
app.component("TabPanel", TabPanel);
app.component("MultiSelect", MultiSelect);
app.component("Tag", Tag);
app.component("Toast", Toast);
app.component("Accordion", Accordion);
app.component("AccordionTab", AccordionTab);
app.component("DataTable", DataTable);
app.component("Column", Column);
app.component("DynamicDialog", DynamicDialog);
app.component("ProgressSpinner", ProgressSpinner);
app.component("Checkbox", Checkbox);
app.component("Skeleton", Skeleton);
app.component("Calendar", Calendar);
},
)
export {router}

View File

@ -14,24 +14,22 @@
//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/>.
import { createRouter, createWebHistory } from "vue-router";
import { createMemoryHistory, RouterOptions, createWebHistory } from "vue-router";
const Faq = () => import("../components/FaqPage.vue");
const AdditionalModules = () => import("../view/AdditionalModules.vue");
const CalendarLink = () => import("../components/CalendarLink.vue");
const RenameModules = () => import("../components/RenameModules.vue");
const RoomFinder = () => import("../view/RoomFinder.vue");
const EditCalendarView = () => import("../view/EditCalendarView.vue");
const EditAdditionalModules = () =>
import("../view/editCalendar/EditAdditionalModules.vue");
const EditModules = () => import("../view/editCalendar/EditModules.vue");
const CourseSelection = () => import("../view/CourseSelection.vue");
const FreeRooms = () => import("../view/FreeRooms.vue");
const AdditionalModules = () => import("../view/create/AdditionalModules.vue");
const CalendarLink = () => import("../view/CalendarLink.vue");
const RenameModules = () => import("../view/create/RenameModules.vue");
const RoomFinder = () => import("../view/rooms/RoomFinder.vue");
const FreeRooms = () => import("../view/rooms/FreeRooms.vue");
const EditCalendarView = () => import("../view/edit/EditCalendar.vue");
const EditAdditionalModules = () =>
import("../view/edit/EditAdditionalModules.vue");
const EditModules = () => import("../view/edit/EditModules.vue");
const FaqView = () => import("../view/FaqView.vue");
import i18n from "../i18n";
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
const routes : RouterOptions = {
history: import.meta.env.SSR ? createMemoryHistory(import.meta.env.BASE_URL) : createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: "/",
@ -47,6 +45,7 @@ const router = createRouter({
component: RoomFinder,
meta: {
label: "roomFinderPage.roomSchedule",
description: "roomFinderPage.description",
},
},
{
@ -55,14 +54,16 @@ const router = createRouter({
component: FreeRooms,
meta: {
label: "freeRooms.freeRooms",
}
description: "freeRooms.description",
},
},
{
path: "/faq",
name: "faq",
component: Faq,
component: FaqView,
meta: {
label: "faq",
description: "faqView.description",
}
},
{
@ -79,6 +80,7 @@ const router = createRouter({
component: EditAdditionalModules,
meta: {
label: "editCalendar",
description: "editCalendarView.description"
}
},
{
@ -87,6 +89,7 @@ const router = createRouter({
component: EditModules,
meta: {
label: "editCalendar",
description: "editCalendarView.description"
}
},
{
@ -103,30 +106,25 @@ const router = createRouter({
component: EditCalendarView,
meta: {
label: "editCalendar",
description: "editCalendarView.description"
}
},
{
path: "/privacy-policy",
name: "privacy-policy",
component: Faq,
beforeEnter() {
window.location.href =
"https://www.htwk-leipzig.de/hochschule/kontakt/datenschutzerklaerung/";
},
component: {},
meta: {
label: "privacy"
label: "privacy",
redirect: "https://www.htwk-leipzig.de/hochschule/kontakt/datenschutzerklaerung/",
}
},
{
path: "/imprint",
name: "imprint",
component: Faq,
beforeEnter() {
window.location.href =
"https://www.htwk-leipzig.de/hochschule/kontakt/impressum/";
},
component: {},
meta: {
label: "imprint"
label: "imprint",
redirect: "https://www.htwk-leipzig.de/hochschule/kontakt/impressum/",
}
},
{
@ -138,16 +136,6 @@ const router = createRouter({
}
},
],
});
};
router.beforeEach(async (to, from) => {
const newLocale = to.params.locale;
const prevLocale = from.params.locale;
// If the locale hasn't changed, do nothing
if (newLocale === prevLocale) {
return;
}
i18n.setLocale(newLocale);
});
export default router;
export default routes;

View File

@ -20,7 +20,7 @@ import { useLocalStorage } from "@vueuse/core";
const localeStore = defineStore("localeStore", {
state: () => {
return {
locale: useLocalStorage("locale", "en"), //useLocalStorage takes in a key of 'count' and default value of 0
locale: useLocalStorage("locale", "de"), //useLocalStorage takes in a key of 'count' and default value of 0
};
},
actions: {

View File

@ -17,16 +17,16 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<script lang="ts" setup>
import tokenStore from "../store/tokenStore.ts";
import tokenStore from "@/store/tokenStore.ts";
import { useToast } from "primevue/usetoast";
import { computed, onMounted } from "vue";
import router from "../router";
import { computed, inject, onMounted } from "vue";
import { router } from "@/main";
import { useI18n } from "vue-i18n";
const { t } = useI18n({ useScope: "global" });
const toast = useToast();
const domain = window.location.hostname;
const domain = inject<string>("domain")!;
const getLink = () =>
"https://" + domain + "/api/feed?token=" + tokenStore().token;

View File

@ -21,13 +21,13 @@ import { computed, ComputedRef, Ref, ref, watch } from "vue";
import {
fetchCourseBySemester,
fetchModulesByCourseAndSemester,
} from "../api/fetchCourse";
import DynamicPage from "./DynamicPage.vue";
import ModuleSelection from "../components/ModuleSelection.vue";
import { Module } from "../model/module.ts";
} from "@/api/fetchCourse";
import DynamicPage from "@/view/DynamicPage.vue";
import ModuleSelection from "@/components/ModuleSelection.vue";
import { Module } from "@/model/module.ts";
import { useI18n } from "vue-i18n";
import moduleStore from "../store/moduleStore";
import router from "../router";
import moduleStore from "@/store/moduleStore";
import { router } from "@/main";
async function getModules() {
modules.value = await fetchModulesByCourseAndSemester(

View File

@ -42,7 +42,7 @@ const hasContent = computed(() => {
</script>
<template>
<heading class="flex flex-column align-items-center mt-0">
<div class="flex flex-column align-items-center mt-0">
<div
class="flex align-items-center justify-content-center gap-3 mx-2 mb-4 transition-rolldown"
:class="{ 'md:mt-8': hideContent }"
@ -87,7 +87,7 @@ const hasContent = computed(() => {
>
<slot name="content"></slot>
</div>
</heading>
</div>
</template>
<style scoped>

View File

@ -17,9 +17,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<script lang="ts" setup>
import moduleStore from "../store/moduleStore";
import router from "../router";
import AdditionalModuleTable from "../components/AdditionalModuleTable.vue";
import moduleStore from "@/store/moduleStore";
import {router} from "@/main";
import AdditionalModuleTable from "@/components/AdditionalModuleTable.vue";
const store = moduleStore();

View File

@ -17,13 +17,13 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<script setup lang="ts">
import moduleStore from "../store/moduleStore.ts";
import { createIndividualFeed } from "../api/createFeed.ts";
import router from "../router";
import tokenStore from "../store/tokenStore.ts";
import moduleStore from "@/store/moduleStore.ts";
import { createIndividualFeed } from "@/api/createFeed.ts";
import { router } from "@/main";
import tokenStore from "@/store/tokenStore.ts";
import { Ref, computed, inject, ref, onMounted } from "vue";
import ModuleTemplateDialog from "./ModuleTemplateDialog.vue";
import { onlyWhitespace } from "../helpers/strings.ts";
import ModuleTemplateDialog from "@/components/ModuleTemplateDialog.vue";
import { onlyWhitespace } from "@/helpers/strings.ts";
import { useI18n } from "vue-i18n";
import { Module } from "@/model/module.ts";
import { useToast } from "primevue/usetoast";

View File

@ -18,12 +18,12 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
<script lang="ts" setup>
import { defineAsyncComponent } from "vue";
import moduleStore from "../../store/moduleStore";
import router from "../../router";
import moduleStore from "@/store/moduleStore";
import { router } from "@/main";
const store = moduleStore();
const AdditionalModuleTable = defineAsyncComponent(
() => import("../../components/AdditionalModuleTable.vue"),
() => import("@/components/AdditionalModuleTable.vue"),
);
async function nextStep() {

View File

@ -18,14 +18,14 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
<script setup lang="ts">
import { Ref, ref } from "vue";
import { Module } from "../model/module";
import moduleStore from "../store/moduleStore";
import { getCalender } from "../api/loadCalendar";
import router from "../router";
import tokenStore from "../store/tokenStore";
import { Module } from "@/model/module";
import moduleStore from "@/store/moduleStore";
import { getCalender } from "@/api/loadCalendar";
import { router } from "@/main";
import tokenStore from "@/store/tokenStore";
import { useToast } from "primevue/usetoast";
import { useI18n } from "vue-i18n";
import DynamicPage from "./DynamicPage.vue";
import DynamicPage from "@/view/DynamicPage.vue";
const { t } = useI18n({ useScope: "global" });
const toast = useToast();

View File

@ -19,12 +19,12 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
<script lang="ts" setup>
import { computed, inject, Ref, ref } from "vue";
import { Module } from "@/model/module.ts";
import moduleStore from "../../store/moduleStore";
import moduleStore from "@/store/moduleStore";
import { fetchAllModules } from "@/api/fetchCourse.ts";
import { deleteIndividualFeed, saveIndividualFeed } from "@/api/createFeed.ts";
import tokenStore from "../../store/tokenStore";
import router from "@/router";
import ModuleTemplateDialog from "../../components/ModuleTemplateDialog.vue";
import tokenStore from "@/store/tokenStore";
import { router } from "@/main";
import ModuleTemplateDialog from "@/components/ModuleTemplateDialog.vue";
import { onlyWhitespace } from "@/helpers/strings.ts";
import { useI18n } from "vue-i18n";
import { useToast } from "primevue/usetoast";

View File

@ -151,7 +151,7 @@ import DynamicPage from "@/view/DynamicPage.vue";
import { requestFreeRooms } from "@/api/requestFreeRooms.ts";
import { FilterMatchMode } from "primevue/api";
import { padStart } from "@fullcalendar/core/internal";
import router from "@/router";
import { router } from "@/main";
import { formatYearMonthDay } from "@/helpers/dates";
const mobilePage = inject("mobilePage") as Ref<boolean>;

View File

@ -18,11 +18,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
<script lang="ts" setup>
import { Ref, computed, ref, watch } from "vue";
import { fetchRoom } from "../api/fetchRoom.ts";
import DynamicPage from "./DynamicPage.vue";
import RoomOccupation from "../components/RoomOccupation.vue";
import { fetchRoom } from "@/api/fetchRoom.ts";
import DynamicPage from "@/view/DynamicPage.vue";
import RoomOccupation from "@/components/RoomOccupation.vue";
import { computedAsync } from "@vueuse/core";
import router from "@/router";
import { router } from "@/main";
type Room = {
name: string;

View File

@ -20,7 +20,8 @@
"noFallthroughCasesInSwitch": true,
"allowSyntheticDefaultImports": true,
"paths": {
"@/*": ["./src/*"]
"@/*": ["./src/*"],
"primevue/*": ["./node_modules/primevue/*"]
}
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],

View File

@ -18,7 +18,12 @@ import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import { fileURLToPath } from "node:url";
import resolve from "@rollup/plugin-node-resolve";
import {resolve as pathResolver} from "path";
import terser from "@rollup/plugin-terser";
import ViteSSGOptions from "vite-ssg";
import generateSitemap from 'vite-ssg-sitemap'
const hostname = "https://cal.htwk-leipzig.de";
// https://vitejs.dev/config/
export default defineConfig({
@ -28,8 +33,27 @@ export default defineConfig({
terser(),
],
resolve: {
alias: {
"@": fileURLToPath(new URL("./src", import.meta.url)),
alias:
{
"@": fileURLToPath(new URL("./src", import.meta.url)),
'primevue' : pathResolver(__dirname, 'node_modules/primevue'),
},
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.css', '.scss'],
},
ssgOptions: {
script: "async",
formatting: "minify",
format: "esm",
onFinished: () => {
generateSitemap({
hostname: hostname,
exclude: [
'/additional-modules',
'/edit-additional-modules',
'/edit-calendar',
'/rename-modules',
]
})
},
},
server: {