blob: c9756128f5bfcfcef38a1063425828d679e46610 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
<template>
<StudipDialog
v-if="displayThemeAddImportDialog"
:title="$gettext('Theme importieren')"
:closeText="$gettext('Schließen')"
:confirmText="$gettext('Importieren')"
closeClass="cancel"
:confirmDisabled="!hasErrors"
confirmClass="upload"
height="500"
width="400"
@close="closeDialog"
@confirm="createThemeFromFile"
>
<template v-slot:dialogContent>
<StudipMessageBox v-if="fileError" :type="'error'" :hideClose="true">
{{ fileError }}
</StudipMessageBox>
<div class="theme-upload-actions">
<input type="file" ref="fileInput" @change="handleFileUpload" accept=".json" class="visually-hidden" />
<div class="file-dropzone-wrapper" @click="triggerFileInput">
<div class="file-dropzone" :class="{ 'has-file': fileSelected }">
<StudipIcon :shape="fileName ? 'file' : 'upload'" :size="48" />
<span>{{
fileName ? fileName : $gettext('Theme-Datei auswählen oder via Drag and Drop hinzufügen')
}}</span>
</div>
</div>
</div>
</template>
</StudipDialog>
</template>
<script setup>
import { computed, getCurrentInstance, ref } from 'vue';
import StudipDialog from '../StudipDialog.vue';
import StudipMessageBox from '../StudipMessageBox.vue';
import { useStore } from 'vuex';
const { proxy } = getCurrentInstance()
const store = useStore();
const displayThemeAddImportDialog = computed(() => store.getters['theme-settings-module/showThemeAddImportDialog']);
const hasErrors = computed(() => !fileError.value && fileSelected.value && jsonData.value);
const showThemeAddImportDialog = (show) => {
store.dispatch('theme-settings-module/setShowThemeAddImportDialog', show);
};
const fileInput = ref(null);
const fileSelected = ref(false);
const fileName = ref('');
const jsonData = ref(null);
const fileError = ref(null);
const triggerFileInput = () => {
fileInput.value?.click();
};
const isValidThemeData = (data) => {
if (typeof data !== 'object' || data === null) return false;
if (typeof data.name !== 'string' || data.name.trim() === '') return false;
if (data.description && typeof data.description !== 'string') return false;
if (data.type && !['light', 'dark', 'high-contrast'].includes(data.type)) return false;
if (typeof data.values !== 'object' || data.values === null || Array.isArray(data.values)) return false;
return true;
};
const handleFileUpload = (event) => {
fileSelected.value = false;
jsonData.value = null;
fileError.value = null;
fileName.value = '';
const file = event.target.files[0];
if (file && file.type === 'application/json') {
fileName.value = file.name;
const reader = new FileReader();
reader.onload = () => {
try {
const parsed = JSON.parse(reader.result);
if (isValidThemeData(parsed)) {
jsonData.value = parsed;
fileSelected.value = true;
} else {
fileError.value = proxy.$gettext('Die JSON-Datei enthält keine gültigen Themendaten.');
}
} catch {
fileError.value = proxy.$gettext('Ungültiges JSON-Format.');
}
};
reader.readAsText(file);
} else {
fileError.value = proxy.$gettext('Bitte laden Sie eine gültige .json-Datei hoch.');
}
};
const createThemeFromFile = async () => {
if (jsonData.value) {
const newTheme = {
attributes: {
name: jsonData.value.name,
description: jsonData.value.description || '',
type: jsonData.value.type || 'light',
values: jsonData.value.values,
},
};
await store.dispatch('theme-settings-module/createThemeFromData', { theme: newTheme });
fileSelected.value = false;
jsonData.value = null;
fileName.value = '';
showThemeAddImportDialog(false);
}
};
const closeDialog = () => {
removeFile();
showThemeAddImportDialog(false);
};
const removeFile = () => {
fileInput.value.value = '';
fileSelected.value = false;
fileName.value = '';
jsonData.value = null;
fileError.value = null;
};
</script>
|