diff --git a/package-lock.json b/package-lock.json
index 9115863..298e1fb 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,6 +10,7 @@
"license": "GPL-3.0-or-later",
"dependencies": {
"dayjs": "^1.11.3",
+ "downloadjs": "^1.4.7",
"lucide-vue-next": "^0.233.0",
"swiper": "^9.3.2",
"vue": "^3.2.37",
@@ -3108,6 +3109,11 @@
"node": ">=6.0.0"
}
},
+ "node_modules/downloadjs": {
+ "version": "1.4.7",
+ "resolved": "https://registry.npmjs.org/downloadjs/-/downloadjs-1.4.7.tgz",
+ "integrity": "sha512-LN1gO7+u9xjU5oEScGFKvXhYf7Y/empUIIEAGBs1LzUq/rg5duiDrkuH5A2lQGd5jfMOb9X9usDa2oVXwJ0U/Q=="
+ },
"node_modules/ejs": {
"version": "3.1.9",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz",
diff --git a/package.json b/package.json
index 8a8a563..8e3f653 100644
--- a/package.json
+++ b/package.json
@@ -11,6 +11,7 @@
},
"dependencies": {
"dayjs": "^1.11.3",
+ "downloadjs": "^1.4.7",
"lucide-vue-next": "^0.233.0",
"swiper": "^9.3.2",
"vue": "^3.2.37",
diff --git a/src/components/settings/timetable-card.vue b/src/components/settings/timetable-card.vue
index 02efa1c..8ccf196 100644
--- a/src/components/settings/timetable-card.vue
+++ b/src/components/settings/timetable-card.vue
@@ -8,9 +8,10 @@ import {
AlertCircleIcon,
CopyIcon,
} from "lucide-vue-next";
+import { DownloadIcon } from "lucide-vue-next";
defineProps(["timetable", "editable", "selected"]);
-defineEmits(["click", "edit", "delete", "copy"]);
+defineEmits(["click", "edit", "delete", "copy", "export"]);
const deleteConfirm = ref(false);
@@ -36,6 +37,7 @@ watch(deleteConfirm, (value) => {
+
import TimetableCard from "@/components/settings/timetable-card.vue";
import { timetables, localTimetables, timetableId } from "@/store";
-import { PlusIcon } from "lucide-vue-next";
-import { toRaw } from "vue";
+import { PlusIcon, PaperclipIcon } from "lucide-vue-next";
+import { toRaw, ref } from "vue";
+import download from "downloadjs";
function copyTimetable(timetable) {
const newTimetable = structuredClone(toRaw(timetable));
@@ -18,6 +19,33 @@ function createTimetable() {
data: [],
});
}
+
+const fileInput = ref();
+function importTimetable(event) {
+ const file = event.target.files[0];
+ if (!file) return;
+
+ const reader = new FileReader();
+ reader.onload = (e) => {
+ const contents = e.target.result;
+ try {
+ const data = JSON.parse(contents);
+ if (!data.data) throw "Invalid data";
+ localTimetables.value.push(data);
+ } catch (e) {
+ alert("Import failed! Check your timetable file!");
+ }
+ };
+ reader.readAsText(file);
+}
+
+function exportTimetable(timetable) {
+ download(
+ JSON.stringify(timetable),
+ `timetable-${timetable.id}.json`,
+ "application/json"
+ );
+}
@@ -39,10 +67,22 @@ function createTimetable() {
1
)
"
+ @export="exportTimetable(timetable)"
/>
-
-
{{ $t("settings.text.createTimetable") }}
+
{{ $t("settings.heading.remoteTimetables") }}
@@ -54,6 +94,7 @@ function createTimetable() {
:editable="false"
@click="timetableId = timetable.id"
@copy="copyTimetable(timetable)"
+ @export="exportTimetable(timetable)"
/>
@@ -74,12 +115,22 @@ p {
gap: 8px;
}
-.create {
- display: flex;
+.buttons {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
justify-content: center;
align-items: center;
margin-top: 5px;
+ user-select: none;
+}
+
+.create,
+.import {
+ display: flex;
+ justify-content: center;
+ align-items: center;
padding: 10px;
+ gap: 5px;
cursor: pointer;
}