mktcms 0.2.7 → 0.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -8
- package/dist/module.json +1 -1
- package/dist/module.mjs +19 -1
- package/dist/runtime/app/components/content/editor/frontmatter/form.d.vue.ts +14 -6
- package/dist/runtime/app/components/content/editor/frontmatter/form.vue +285 -17
- package/dist/runtime/app/components/content/editor/frontmatter/form.vue.d.ts +14 -6
- package/dist/runtime/app/components/content/editor/frontmatter/input.d.vue.ts +7 -5
- package/dist/runtime/app/components/content/editor/frontmatter/input.vue +27 -8
- package/dist/runtime/app/components/content/editor/frontmatter/input.vue.d.ts +7 -5
- package/dist/runtime/app/components/content/editor/frontmatter/{toggle.d.vue.ts → modal.d.vue.ts} +7 -4
- package/dist/runtime/app/components/content/editor/frontmatter/modal.vue +113 -0
- package/dist/runtime/app/components/content/editor/frontmatter/{toggle.vue.d.ts → modal.vue.d.ts} +7 -4
- package/dist/runtime/app/components/content/editor/markdown.vue +14 -3
- package/dist/runtime/app/components/content/versioning.d.vue.ts +3 -0
- package/dist/runtime/app/components/content/versioning.vue +359 -0
- package/dist/runtime/app/components/content/versioning.vue.d.ts +3 -0
- package/dist/runtime/app/composables/useFileType.js +6 -5
- package/dist/runtime/app/pages/admin/delete/[path].vue +4 -2
- package/dist/runtime/app/pages/admin/edit/file/[path].vue +9 -7
- package/dist/runtime/app/pages/admin/edit/markdown/[path].vue +7 -5
- package/dist/runtime/app/pages/admin/index.vue +14 -5
- package/dist/runtime/app/pages/admin/new.vue +4 -2
- package/dist/runtime/app/styles/admin.css +1 -1
- package/dist/runtime/app/styles/admin.min.css +1 -1
- package/dist/runtime/server/api/admin/git-branch.d.ts +18 -0
- package/dist/runtime/server/api/admin/git-branch.js +44 -0
- package/dist/runtime/server/api/admin/git-history.d.ts +2 -0
- package/dist/runtime/server/api/admin/git-history.js +27 -0
- package/dist/runtime/server/api/admin/git-update-status.d.ts +2 -0
- package/dist/runtime/server/api/admin/git-update-status.js +21 -0
- package/dist/runtime/server/api/admin/git-update.post.d.ts +6 -0
- package/dist/runtime/server/api/admin/git-update.post.js +45 -0
- package/dist/runtime/server/utils/gitVersioning.d.ts +54 -0
- package/dist/runtime/server/utils/gitVersioning.js +205 -0
- package/dist/runtime/server/utils/syncGitContent.js +20 -10
- package/package.json +2 -1
- package/dist/runtime/app/components/content/editor/frontmatter/toggle.vue +0 -22
package/dist/runtime/app/components/content/editor/frontmatter/{toggle.vue.d.ts → modal.vue.d.ts}
RENAMED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
type __VLS_Props = {
|
|
2
|
-
|
|
2
|
+
isOpen: boolean;
|
|
3
3
|
};
|
|
4
4
|
type __VLS_ModelProps = {
|
|
5
|
-
'
|
|
5
|
+
'frontmatter': any;
|
|
6
6
|
};
|
|
7
7
|
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
8
8
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
9
|
-
"update:
|
|
9
|
+
"update:frontmatter": (value: any) => any;
|
|
10
|
+
} & {
|
|
11
|
+
close: () => any;
|
|
10
12
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
11
|
-
|
|
13
|
+
onClose?: (() => any) | undefined;
|
|
14
|
+
"onUpdate:frontmatter"?: ((value: any) => any) | undefined;
|
|
12
15
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
13
16
|
declare const _default: typeof __VLS_export;
|
|
14
17
|
export default _default;
|
|
@@ -4,7 +4,7 @@ import { refDebounced } from "@vueuse/core";
|
|
|
4
4
|
import Saved from "../saved.vue";
|
|
5
5
|
import usePathParam from "../../../composables/usePathParam";
|
|
6
6
|
import { useFetch } from "#imports";
|
|
7
|
-
import
|
|
7
|
+
import FrontmatterModal from "./frontmatter/modal.vue";
|
|
8
8
|
import MonacoEditor from "./monacoEditor.vue";
|
|
9
9
|
const { path } = usePathParam();
|
|
10
10
|
const { data: content } = await useFetch(`/api/admin/md?path=${path}`);
|
|
@@ -14,6 +14,7 @@ const commitMessage = ref("Inhaltliche \xC4nderungen");
|
|
|
14
14
|
const debouncedMarkdown = refDebounced(markdown, 250);
|
|
15
15
|
const isSaving = ref(false);
|
|
16
16
|
const savingSuccessful = ref(false);
|
|
17
|
+
const showFrontmatterModal = ref(false);
|
|
17
18
|
async function saveMarkdown() {
|
|
18
19
|
if (!content.value) return;
|
|
19
20
|
isSaving.value = true;
|
|
@@ -37,10 +38,20 @@ const mode = ref("preview");
|
|
|
37
38
|
v-if="content"
|
|
38
39
|
class="flex-1 min-h-0 flex flex-col"
|
|
39
40
|
>
|
|
40
|
-
<
|
|
41
|
+
<button
|
|
42
|
+
type="button"
|
|
43
|
+
class="button secondary small mb-3 self-start"
|
|
44
|
+
@click="showFrontmatterModal = true"
|
|
45
|
+
>
|
|
46
|
+
Metadaten bearbeiten
|
|
47
|
+
</button>
|
|
48
|
+
|
|
49
|
+
<FrontmatterModal
|
|
41
50
|
v-model:frontmatter="frontmatter"
|
|
42
|
-
|
|
51
|
+
:is-open="showFrontmatterModal"
|
|
52
|
+
@close="showFrontmatterModal = false"
|
|
43
53
|
/>
|
|
54
|
+
|
|
44
55
|
<div class="flex gap-2 my-2 lg:hidden">
|
|
45
56
|
<button
|
|
46
57
|
type="button"
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
declare const _default: typeof __VLS_export;
|
|
3
|
+
export default _default;
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed, ref } from "vue";
|
|
3
|
+
import { useFetch } from "#app";
|
|
4
|
+
const HISTORY_PER_PAGE = 25;
|
|
5
|
+
const isHistoryModalOpen = ref(false);
|
|
6
|
+
const isUpdateModalOpen = ref(false);
|
|
7
|
+
const selectedUpdateBranch = ref("");
|
|
8
|
+
const historyPage = ref(1);
|
|
9
|
+
const isUpdating = ref(false);
|
|
10
|
+
const updateError = ref("");
|
|
11
|
+
const updateSuccess = ref("");
|
|
12
|
+
const { data: branchData, pending: branchPending, error: branchError, refresh: refreshBranch } = await useFetch("/api/admin/git-branch", {
|
|
13
|
+
key: "mktcms-git-branch"
|
|
14
|
+
});
|
|
15
|
+
const { data: updateStatusData, pending: updateStatusPending, error: updateStatusError, refresh: refreshUpdateStatus } = await useFetch("/api/admin/git-update-status", {
|
|
16
|
+
key: "mktcms-git-update-status"
|
|
17
|
+
});
|
|
18
|
+
const { data: historyData, pending: historyPending, error: historyError, refresh: refreshHistory } = await useFetch("/api/admin/git-history", {
|
|
19
|
+
key: "mktcms-git-history",
|
|
20
|
+
query: computed(() => ({
|
|
21
|
+
page: historyPage.value,
|
|
22
|
+
perPage: HISTORY_PER_PAGE
|
|
23
|
+
})),
|
|
24
|
+
immediate: false
|
|
25
|
+
});
|
|
26
|
+
const currentBranch = computed(() => branchData.value?.currentBranch ?? "unbekannt");
|
|
27
|
+
const isSupportedBranch = computed(() => branchData.value?.isSupported ?? false);
|
|
28
|
+
const sourceBranch = computed(() => branchData.value?.sourceBranch ?? "");
|
|
29
|
+
const sourceAheadCount = computed(() => updateStatusData.value?.sourceAheadCount ?? 0);
|
|
30
|
+
const isIdentical = computed(() => updateStatusData.value?.isIdentical ?? false);
|
|
31
|
+
const canUpdate = computed(() => updateStatusData.value?.canUpdate ?? false);
|
|
32
|
+
const updateBlockedReason = computed(() => updateStatusData.value?.updateBlockedReason || branchData.value?.updateBlockedReason || "");
|
|
33
|
+
const updateButtonText = computed(() => {
|
|
34
|
+
const count = sourceAheadCount.value;
|
|
35
|
+
return `Aktualisieren (${count})`;
|
|
36
|
+
});
|
|
37
|
+
const updateTitle = computed(() => currentBranch.value === "main" ? "\xC4nderungen aus Vorschau \xFCbernehmen" : currentBranch.value === "staging" ? "\xC4nderungen von Live in Vorschau \xFCbernehmen" : "Branch aktualisieren");
|
|
38
|
+
const historyEntries = computed(() => historyData.value?.entries ?? []);
|
|
39
|
+
const hasNextHistoryPage = computed(() => historyData.value?.hasNextPage ?? false);
|
|
40
|
+
function formatRelativeDate(isoDate) {
|
|
41
|
+
const target = new Date(isoDate).getTime();
|
|
42
|
+
if (!Number.isFinite(target)) {
|
|
43
|
+
return isoDate;
|
|
44
|
+
}
|
|
45
|
+
const diffMs = target - Date.now();
|
|
46
|
+
const absMs = Math.abs(diffMs);
|
|
47
|
+
const minute = 6e4;
|
|
48
|
+
const hour = 60 * minute;
|
|
49
|
+
const day = 24 * hour;
|
|
50
|
+
const rtf = new Intl.RelativeTimeFormat("de-DE", { numeric: "auto" });
|
|
51
|
+
if (absMs < hour) {
|
|
52
|
+
return rtf.format(Math.round(diffMs / minute), "minute");
|
|
53
|
+
}
|
|
54
|
+
if (absMs < day) {
|
|
55
|
+
return rtf.format(Math.round(diffMs / hour), "hour");
|
|
56
|
+
}
|
|
57
|
+
return rtf.format(Math.round(diffMs / day), "day");
|
|
58
|
+
}
|
|
59
|
+
async function openHistoryModal() {
|
|
60
|
+
isHistoryModalOpen.value = true;
|
|
61
|
+
historyPage.value = 1;
|
|
62
|
+
await refreshHistory();
|
|
63
|
+
}
|
|
64
|
+
function openUpdateModal() {
|
|
65
|
+
selectedUpdateBranch.value = updateStatusData.value?.sourceBranch || sourceBranch.value;
|
|
66
|
+
updateError.value = "";
|
|
67
|
+
updateSuccess.value = "";
|
|
68
|
+
isUpdateModalOpen.value = true;
|
|
69
|
+
}
|
|
70
|
+
function closeHistoryModal() {
|
|
71
|
+
isHistoryModalOpen.value = false;
|
|
72
|
+
}
|
|
73
|
+
async function goToHistoryPage(nextPage) {
|
|
74
|
+
if (nextPage < 1 || historyPending.value) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
historyPage.value = nextPage;
|
|
78
|
+
await refreshHistory();
|
|
79
|
+
}
|
|
80
|
+
function closeUpdateModal() {
|
|
81
|
+
isUpdateModalOpen.value = false;
|
|
82
|
+
}
|
|
83
|
+
async function runUpdate() {
|
|
84
|
+
if (!isSupportedBranch.value || isUpdating.value) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (!canUpdate.value) {
|
|
88
|
+
updateError.value = updateBlockedReason.value || "Aktualisierung aktuell nicht m\xF6glich.";
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
isUpdating.value = true;
|
|
92
|
+
updateError.value = "";
|
|
93
|
+
updateSuccess.value = "";
|
|
94
|
+
try {
|
|
95
|
+
await $fetch("/api/admin/git-update", {
|
|
96
|
+
method: "POST"
|
|
97
|
+
});
|
|
98
|
+
updateSuccess.value = `Merge erfolgreich: ${sourceBranch.value} \u2192 ${currentBranch.value}`;
|
|
99
|
+
await refreshBranch();
|
|
100
|
+
await refreshUpdateStatus();
|
|
101
|
+
} catch (error) {
|
|
102
|
+
updateError.value = error?.data?.statusMessage || error?.message || "Aktualisierung fehlgeschlagen.";
|
|
103
|
+
} finally {
|
|
104
|
+
isUpdating.value = false;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
</script>
|
|
108
|
+
|
|
109
|
+
<template>
|
|
110
|
+
<div class="text-sm text-gray-700">
|
|
111
|
+
<div class="flex items-center justify-end gap-3">
|
|
112
|
+
<span class="text-xs text-gray-500 mr-auto">
|
|
113
|
+
Version: <strong class="capitalize">{{ currentBranch }}</strong>
|
|
114
|
+
</span>
|
|
115
|
+
<button
|
|
116
|
+
type="button"
|
|
117
|
+
class="button small tertiary"
|
|
118
|
+
@click="openHistoryModal"
|
|
119
|
+
>
|
|
120
|
+
<svg
|
|
121
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
122
|
+
width="16"
|
|
123
|
+
height="16"
|
|
124
|
+
viewBox="0 0 24 24"
|
|
125
|
+
fill="none"
|
|
126
|
+
stroke="currentColor"
|
|
127
|
+
stroke-width="2"
|
|
128
|
+
stroke-linecap="round"
|
|
129
|
+
stroke-linejoin="round"
|
|
130
|
+
class="text-gray-400"
|
|
131
|
+
><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" /><path d="M3 3v5h5" /><path d="M12 7v5l4 2" /></svg>
|
|
132
|
+
Änderungshistorie
|
|
133
|
+
</button>
|
|
134
|
+
<button
|
|
135
|
+
type="button"
|
|
136
|
+
class="button small tertiary"
|
|
137
|
+
:disabled="branchPending || updateStatusPending || !!branchError || !!updateStatusError"
|
|
138
|
+
@click="openUpdateModal"
|
|
139
|
+
>
|
|
140
|
+
<svg
|
|
141
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
142
|
+
width="16"
|
|
143
|
+
height="16"
|
|
144
|
+
viewBox="0 0 24 24"
|
|
145
|
+
fill="none"
|
|
146
|
+
stroke="currentColor"
|
|
147
|
+
stroke-width="2"
|
|
148
|
+
stroke-linecap="round"
|
|
149
|
+
stroke-linejoin="round"
|
|
150
|
+
class="text-gray-400"
|
|
151
|
+
><path d="M12 2a10 10 0 0 1 7.38 16.75" /><path d="m16 12-4-4-4 4" /><path d="M12 16V8" /><path d="M2.5 8.875a10 10 0 0 0-.5 3" /><path d="M2.83 16a10 10 0 0 0 2.43 3.4" /><path d="M4.636 5.235a10 10 0 0 1 .891-.857" /><path d="M8.644 21.42a10 10 0 0 0 7.631-.38" /></svg>
|
|
152
|
+
{{ updateButtonText }}
|
|
153
|
+
</button>
|
|
154
|
+
</div>
|
|
155
|
+
|
|
156
|
+
<div
|
|
157
|
+
v-if="isHistoryModalOpen"
|
|
158
|
+
class="fixed inset-0 bg-black/45 flex items-start justify-center p-4 z-9999 overflow-y-auto"
|
|
159
|
+
role="presentation"
|
|
160
|
+
@click.self="closeHistoryModal"
|
|
161
|
+
>
|
|
162
|
+
<div
|
|
163
|
+
class="w-full max-w-140 bg-white rounded-[10px] border border-black/10 shadow-[0_10px_40px_rgba(0,0,0,0.28)] p-6 flex flex-col gap-4 max-h-[calc(100vh-2rem)] my-auto"
|
|
164
|
+
role="dialog"
|
|
165
|
+
aria-modal="true"
|
|
166
|
+
aria-label="Änderungshistorie"
|
|
167
|
+
>
|
|
168
|
+
<div class="flex items-center justify-between gap-2">
|
|
169
|
+
<h2 class="font-bold text-xl">
|
|
170
|
+
Änderungshistorie
|
|
171
|
+
</h2>
|
|
172
|
+
<button
|
|
173
|
+
type="button"
|
|
174
|
+
class="button secondary small"
|
|
175
|
+
@click="closeHistoryModal"
|
|
176
|
+
>
|
|
177
|
+
Schließen
|
|
178
|
+
</button>
|
|
179
|
+
</div>
|
|
180
|
+
|
|
181
|
+
<div class="min-h-0 overflow-y-auto pr-1">
|
|
182
|
+
<div
|
|
183
|
+
v-if="historyError"
|
|
184
|
+
class="text-sm p-3 bg-red-100 text-red-700 rounded"
|
|
185
|
+
>
|
|
186
|
+
Konnte Änderungshistorie nicht laden.
|
|
187
|
+
</div>
|
|
188
|
+
|
|
189
|
+
<div
|
|
190
|
+
v-else-if="historyPending"
|
|
191
|
+
class="text-sm text-gray-500"
|
|
192
|
+
>
|
|
193
|
+
lädt…
|
|
194
|
+
</div>
|
|
195
|
+
|
|
196
|
+
<div
|
|
197
|
+
v-else-if="historyEntries.length === 0"
|
|
198
|
+
class="text-sm text-gray-500"
|
|
199
|
+
>
|
|
200
|
+
Keine Einträge vorhanden.
|
|
201
|
+
</div>
|
|
202
|
+
|
|
203
|
+
<div
|
|
204
|
+
v-else
|
|
205
|
+
class="flex flex-col gap-3"
|
|
206
|
+
>
|
|
207
|
+
<div
|
|
208
|
+
v-for="entry in historyEntries"
|
|
209
|
+
:key="entry.hash"
|
|
210
|
+
class="flex flex-col justify-between gap-3 p-3 bg-gray-50 border border-gray-200 rounded"
|
|
211
|
+
>
|
|
212
|
+
<div class="flex items-start justify-between gap-3 flex-1 w-full">
|
|
213
|
+
<div>
|
|
214
|
+
<p class="font-bold">
|
|
215
|
+
{{ entry.authorName }}
|
|
216
|
+
</p>
|
|
217
|
+
<p class="text-xs text-gray-500 break-all">
|
|
218
|
+
{{ entry.authorEmail }}
|
|
219
|
+
</p>
|
|
220
|
+
</div>
|
|
221
|
+
<p class="text-sm text-gray-500">
|
|
222
|
+
{{ formatRelativeDate(entry.date) }}
|
|
223
|
+
</p>
|
|
224
|
+
</div>
|
|
225
|
+
<p>
|
|
226
|
+
Änderung: "{{ entry.subject }}"
|
|
227
|
+
</p>
|
|
228
|
+
</div>
|
|
229
|
+
|
|
230
|
+
<div class="flex items-center justify-between pt-1">
|
|
231
|
+
<button
|
|
232
|
+
type="button"
|
|
233
|
+
class="button secondary small"
|
|
234
|
+
:disabled="historyPage <= 1 || historyPending"
|
|
235
|
+
@click="goToHistoryPage(historyPage - 1)"
|
|
236
|
+
>
|
|
237
|
+
Zurück
|
|
238
|
+
</button>
|
|
239
|
+
<span class="text-xs text-gray-500">
|
|
240
|
+
Seite {{ historyPage }}
|
|
241
|
+
</span>
|
|
242
|
+
<button
|
|
243
|
+
type="button"
|
|
244
|
+
class="button secondary small"
|
|
245
|
+
:disabled="!hasNextHistoryPage || historyPending"
|
|
246
|
+
@click="goToHistoryPage(historyPage + 1)"
|
|
247
|
+
>
|
|
248
|
+
Weiter
|
|
249
|
+
</button>
|
|
250
|
+
</div>
|
|
251
|
+
</div>
|
|
252
|
+
</div>
|
|
253
|
+
</div>
|
|
254
|
+
</div>
|
|
255
|
+
|
|
256
|
+
<div
|
|
257
|
+
v-if="isUpdateModalOpen"
|
|
258
|
+
class="fixed inset-0 bg-black/45 flex items-start justify-center p-4 z-9999 overflow-y-auto"
|
|
259
|
+
role="presentation"
|
|
260
|
+
@click.self="closeUpdateModal"
|
|
261
|
+
>
|
|
262
|
+
<div
|
|
263
|
+
class="w-full max-w-140 bg-white rounded-[10px] border border-black/10 shadow-[0_10px_40px_rgba(0,0,0,0.28)] p-6 flex flex-col gap-4 max-h-[calc(100vh-2rem)] my-auto overflow-y-auto"
|
|
264
|
+
role="dialog"
|
|
265
|
+
aria-modal="true"
|
|
266
|
+
aria-label="Version aktualisieren"
|
|
267
|
+
>
|
|
268
|
+
<div class="flex items-center justify-between gap-2">
|
|
269
|
+
<h2 class="font-bold text-xl">
|
|
270
|
+
{{ updateTitle }}
|
|
271
|
+
</h2>
|
|
272
|
+
<button
|
|
273
|
+
type="button"
|
|
274
|
+
class="button secondary small"
|
|
275
|
+
@click="closeUpdateModal"
|
|
276
|
+
>
|
|
277
|
+
Schließen
|
|
278
|
+
</button>
|
|
279
|
+
</div>
|
|
280
|
+
|
|
281
|
+
<p class="text-sm p-3 bg-gray-50 border border-gray-200 rounded">
|
|
282
|
+
Achtung: Eine Aktualisierung ist sofort auf der Website sichtbar.
|
|
283
|
+
</p>
|
|
284
|
+
|
|
285
|
+
<p
|
|
286
|
+
v-if="branchError"
|
|
287
|
+
class="text-sm p-3 bg-red-100 text-red-700 rounded"
|
|
288
|
+
>
|
|
289
|
+
Konnte aktuellen Branch nicht laden.
|
|
290
|
+
</p>
|
|
291
|
+
|
|
292
|
+
<p
|
|
293
|
+
v-else-if="updateStatusError"
|
|
294
|
+
class="text-sm p-3 bg-red-100 text-red-700 rounded"
|
|
295
|
+
>
|
|
296
|
+
Konnte Branch-Status nicht laden.
|
|
297
|
+
</p>
|
|
298
|
+
|
|
299
|
+
<p
|
|
300
|
+
v-else-if="isIdentical"
|
|
301
|
+
class="text-sm p-3 bg-gray-50 border border-gray-200 rounded"
|
|
302
|
+
>
|
|
303
|
+
Die Branches sind identisch. Es sind keine neuen Änderungen verfügbar.
|
|
304
|
+
</p>
|
|
305
|
+
|
|
306
|
+
<p
|
|
307
|
+
v-else-if="!isSupportedBranch || !canUpdate"
|
|
308
|
+
class="text-sm p-3 bg-red-100 text-red-700 rounded"
|
|
309
|
+
>
|
|
310
|
+
{{ updateBlockedReason || `Unterst\xFCtzt sind nur main oder staging. Aktuell: ${currentBranch}` }}
|
|
311
|
+
</p>
|
|
312
|
+
|
|
313
|
+
<label class="text-sm font-medium text-gray-700">
|
|
314
|
+
Merge von Branch
|
|
315
|
+
</label>
|
|
316
|
+
<select
|
|
317
|
+
v-model="selectedUpdateBranch"
|
|
318
|
+
class="w-full border border-gray-200 rounded-sm px-3 py-2"
|
|
319
|
+
:disabled="true"
|
|
320
|
+
>
|
|
321
|
+
<option :value="selectedUpdateBranch || ''">
|
|
322
|
+
{{ selectedUpdateBranch || "unbekannt" }}
|
|
323
|
+
</option>
|
|
324
|
+
</select>
|
|
325
|
+
|
|
326
|
+
<p
|
|
327
|
+
v-if="updateError"
|
|
328
|
+
class="text-sm p-3 bg-red-100 text-red-700 rounded"
|
|
329
|
+
>
|
|
330
|
+
{{ updateError }}
|
|
331
|
+
</p>
|
|
332
|
+
<p
|
|
333
|
+
v-if="updateSuccess"
|
|
334
|
+
class="text-sm p-3 bg-emerald-100 text-emerald-800 rounded"
|
|
335
|
+
>
|
|
336
|
+
{{ updateSuccess }}
|
|
337
|
+
</p>
|
|
338
|
+
|
|
339
|
+
<div class="flex items-center justify-end gap-2">
|
|
340
|
+
<button
|
|
341
|
+
type="button"
|
|
342
|
+
class="button secondary small"
|
|
343
|
+
@click="closeUpdateModal"
|
|
344
|
+
>
|
|
345
|
+
Abbrechen
|
|
346
|
+
</button>
|
|
347
|
+
<button
|
|
348
|
+
type="button"
|
|
349
|
+
class="button small"
|
|
350
|
+
:disabled="!isSupportedBranch || !canUpdate || isUpdating || isIdentical"
|
|
351
|
+
@click="runUpdate"
|
|
352
|
+
>
|
|
353
|
+
{{ isUpdating ? "Aktualisiert\u2026" : "Aktualisieren" }}
|
|
354
|
+
</button>
|
|
355
|
+
</div>
|
|
356
|
+
</div>
|
|
357
|
+
</div>
|
|
358
|
+
</div>
|
|
359
|
+
</template>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
declare const _default: typeof __VLS_export;
|
|
3
|
+
export default _default;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
export default function useFileType(path) {
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
2
|
+
const normalizedPath = path.toLowerCase();
|
|
3
|
+
const isImage = normalizedPath.match(/\.(png|jpg|jpeg|gif|webp)$/) !== null;
|
|
4
|
+
const isPdf = normalizedPath.endsWith(".pdf");
|
|
5
|
+
const isMarkdown = normalizedPath.endsWith(".md");
|
|
6
|
+
const isCsv = normalizedPath.endsWith(".csv");
|
|
7
|
+
const isText = normalizedPath.match(/\.(txt|json)$/) !== null;
|
|
7
8
|
return {
|
|
8
9
|
isImage,
|
|
9
10
|
isPdf,
|
|
@@ -11,13 +11,15 @@ const { isImage, isPdf, isCsv, isText } = usePathParam();
|
|
|
11
11
|
|
|
12
12
|
<template>
|
|
13
13
|
<Admin>
|
|
14
|
-
<
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
<div class="boxed">
|
|
15
|
+
<Header />
|
|
16
|
+
<Image v-if="isImage" />
|
|
17
|
+
<Pdf v-else-if="isPdf" />
|
|
18
|
+
<Csv v-else-if="isCsv" />
|
|
19
|
+
<Txt v-else-if="isText" />
|
|
20
|
+
<div v-else>
|
|
21
|
+
Unbekannter Dateityp.
|
|
22
|
+
</div>
|
|
21
23
|
</div>
|
|
22
24
|
</Admin>
|
|
23
25
|
</template>
|
|
@@ -7,11 +7,13 @@ const { isMarkdown } = usePathParam();
|
|
|
7
7
|
</script>
|
|
8
8
|
|
|
9
9
|
<template>
|
|
10
|
-
<Admin
|
|
11
|
-
<
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
<Admin>
|
|
11
|
+
<div class="fullscreen">
|
|
12
|
+
<Header />
|
|
13
|
+
<Markdown v-if="isMarkdown" />
|
|
14
|
+
<div v-else>
|
|
15
|
+
Unbekannter Dateityp.
|
|
16
|
+
</div>
|
|
15
17
|
</div>
|
|
16
18
|
</Admin>
|
|
17
19
|
</template>
|
|
@@ -2,15 +2,24 @@
|
|
|
2
2
|
import Admin from "../../components/admin.vue";
|
|
3
3
|
import Header from "../../components/header.vue";
|
|
4
4
|
import Content from "../../components/content/index.vue";
|
|
5
|
+
import Versioning from "../../components/content/versioning.vue";
|
|
5
6
|
import Usage from "../../components/content/usage.vue";
|
|
7
|
+
import { useRuntimeConfig } from "#imports";
|
|
8
|
+
const { public: { mktcms: { showVersioning } } } = useRuntimeConfig();
|
|
6
9
|
</script>
|
|
7
10
|
|
|
8
11
|
<template>
|
|
9
12
|
<Admin>
|
|
10
|
-
<
|
|
11
|
-
|
|
13
|
+
<div class="boxed">
|
|
14
|
+
<Header class="mb-4" />
|
|
15
|
+
<Content />
|
|
16
|
+
<Versioning
|
|
17
|
+
v-if="showVersioning"
|
|
18
|
+
class="mt-6"
|
|
19
|
+
/>
|
|
20
|
+
</div>
|
|
21
|
+
<div class="mt-6 max-w-3xl mx-auto p-4 border border-gray-200 rounded-2xl">
|
|
22
|
+
<Usage />
|
|
23
|
+
</div>
|
|
12
24
|
</Admin>
|
|
13
|
-
<div class="mt-6 max-w-3xl mx-auto">
|
|
14
|
-
<Usage />
|
|
15
|
-
</div>
|
|
16
25
|
</template>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
@import "tailwindcss";@plugin "@tailwindcss/typography";body:has(#mktcms-admin){@apply bg-gray-100}
|
|
1
|
+
@import "tailwindcss";@plugin "@tailwindcss/typography";body:has(#mktcms-admin){@apply bg-gray-100}#mktcms-admin .boxed{@apply p-4 max-w-3xl mx-auto md:my-6 bg-white md:rounded-lg shadow-lg flex flex-col}#mktcms-admin .fullscreen{@apply max-w-none rounded-none max-h-screen h-screen overflow-hidden bg-white p-3 md:p-6 flex flex-col}#mktcms-admin h1{@apply text-gray-800 text-3xl font-semibold}#mktcms-admin input[type=email],#mktcms-admin input[type=password],#mktcms-admin input[type=text],#mktcms-admin select,#mktcms-admin textarea{@apply w-full bg-white p-2.5 text-base border border-gray-300 rounded}#mktcms-admin .button{@apply inline-flex items-center gap-2 px-4 py-2.5 bg-emerald-600 text-white rounded hover:bg-emerald-700 cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed}#mktcms-admin .button.secondary{@apply bg-gray-50 text-gray-700 border border-gray-300 hover:bg-gray-100}#mktcms-admin .button.tertiary{@apply bg-transparent text-gray-500 border border-gray-100 hover:bg-gray-100 hover:text-gray-700}#mktcms-admin .button.directory{@apply bg-gray-700 text-white border border-gray-600 hover:bg-gray-600}#mktcms-admin .button.danger{@apply bg-red-600 hover:bg-red-700}#mktcms-admin .button.small{@apply px-2.5 py-1.5 text-sm}#mktcms-admin .button :disabled{@apply cursor-not-allowed opacity-50}
|