Add WYSIWYG text editor for Satzung content management
Some checks failed
Code Analysis (JS/Vue) / analyze (push) Failing after 50s
Some checks failed
Code Analysis (JS/Vue) / analyze (push) Failing after 50s
This commit introduces a new WYSIWYG text editor for editing the Satzung text directly within the CMS. It includes functionality for saving the edited content and displays a success or error message based on the save operation's outcome. Additionally, the layout has been updated to improve the presentation of the PDF upload section and current PDF information.
This commit is contained in:
@@ -7,6 +7,7 @@
|
|||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 1. PDF-Upload -->
|
||||||
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-6 mb-6">
|
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-6 mb-6">
|
||||||
<h2 class="text-xl font-semibold mb-4">
|
<h2 class="text-xl font-semibold mb-4">
|
||||||
PDF-Upload
|
PDF-Upload
|
||||||
@@ -68,14 +69,15 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 2. Aktuelle PDF-Information -->
|
||||||
<div
|
<div
|
||||||
v-if="currentPdfUrl"
|
v-if="currentPdfUrl"
|
||||||
class="bg-white rounded-xl shadow-sm border border-gray-200 p-6"
|
class="bg-white rounded-xl shadow-sm border border-gray-200 p-6 mb-6"
|
||||||
>
|
>
|
||||||
<h2 class="text-xl font-semibold mb-4">
|
<h2 class="text-xl font-semibold mb-4">
|
||||||
Aktuelle Satzung
|
Aktuelle Satzung (PDF)
|
||||||
</h2>
|
</h2>
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<p class="text-gray-600">
|
<p class="text-gray-600">
|
||||||
PDF-Datei verfügbar
|
PDF-Datei verfügbar
|
||||||
@@ -94,6 +96,52 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 3. Textfassung (WYSIWYG) -->
|
||||||
|
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-6 mb-6">
|
||||||
|
<div class="flex items-center justify-between mb-4">
|
||||||
|
<h2 class="text-xl font-semibold">
|
||||||
|
Textfassung für die Website
|
||||||
|
</h2>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="inline-flex items-center px-4 py-2 rounded-lg bg-primary-600 text-white hover:bg-primary-700 disabled:opacity-50 disabled:cursor-not-allowed text-sm"
|
||||||
|
:disabled="savingText"
|
||||||
|
@click="saveText"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
v-if="savingText"
|
||||||
|
class="animate-spin -ml-1 mr-2 h-4 w-4 text-white"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<circle
|
||||||
|
class="opacity-25"
|
||||||
|
cx="12"
|
||||||
|
cy="12"
|
||||||
|
r="10"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="4"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
class="opacity-75"
|
||||||
|
fill="currentColor"
|
||||||
|
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
{{ savingText ? 'Speichert...' : 'Text speichern' }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-gray-500 mb-4">
|
||||||
|
Diese HTML-Fassung wird auf der Seite „Verein → Satzung“ angezeigt. Die PDF-Version bleibt die rechtlich verbindliche Fassung.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<RichTextEditor
|
||||||
|
v-model="satzungContent"
|
||||||
|
label="Satzung (HTML-Version)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
v-if="message"
|
v-if="message"
|
||||||
class="mt-4 p-4 rounded-lg"
|
class="mt-4 p-4 rounded-lg"
|
||||||
@@ -107,6 +155,7 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted } from 'vue'
|
||||||
|
import RichTextEditor from '~/components/RichTextEditor.vue'
|
||||||
|
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
middleware: 'auth',
|
middleware: 'auth',
|
||||||
@@ -121,6 +170,8 @@ const currentPdfUrl = ref('')
|
|||||||
const lastUpdated = ref('')
|
const lastUpdated = ref('')
|
||||||
const message = ref('')
|
const message = ref('')
|
||||||
const messageType = ref('')
|
const messageType = ref('')
|
||||||
|
const satzungContent = ref('')
|
||||||
|
const savingText = ref(false)
|
||||||
|
|
||||||
async function loadCurrentSatzung() {
|
async function loadCurrentSatzung() {
|
||||||
try {
|
try {
|
||||||
@@ -131,6 +182,11 @@ async function loadCurrentSatzung() {
|
|||||||
// Einfache Zeitstempel-Simulation
|
// Einfache Zeitstempel-Simulation
|
||||||
lastUpdated.value = new Date().toLocaleDateString('de-DE')
|
lastUpdated.value = new Date().toLocaleDateString('de-DE')
|
||||||
}
|
}
|
||||||
|
if (satzung?.content) {
|
||||||
|
satzungContent.value = satzung.content
|
||||||
|
} else {
|
||||||
|
satzungContent.value = ''
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Fehler beim Laden der aktuellen Satzung:', e)
|
console.error('Fehler beim Laden der aktuellen Satzung:', e)
|
||||||
}
|
}
|
||||||
@@ -187,5 +243,51 @@ async function uploadPdf() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function saveText() {
|
||||||
|
savingText.value = true
|
||||||
|
message.value = ''
|
||||||
|
try {
|
||||||
|
const current = await $fetch('/api/config')
|
||||||
|
const currentSeiten = current.seiten || {}
|
||||||
|
const currentSatzung = currentSeiten.satzung || {}
|
||||||
|
|
||||||
|
const updated = {
|
||||||
|
...current,
|
||||||
|
seiten: {
|
||||||
|
...currentSeiten,
|
||||||
|
satzung: {
|
||||||
|
...currentSatzung,
|
||||||
|
content: satzungContent.value || ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await $fetch('/api/config', {
|
||||||
|
method: 'PUT',
|
||||||
|
body: updated
|
||||||
|
})
|
||||||
|
|
||||||
|
message.value = 'Satzungstext erfolgreich gespeichert'
|
||||||
|
messageType.value = 'success'
|
||||||
|
|
||||||
|
try {
|
||||||
|
window.showSuccessModal && window.showSuccessModal('Erfolg', 'Satzungstext erfolgreich gespeichert.')
|
||||||
|
} catch {
|
||||||
|
// Modal optional
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
const errMsg = error?.data?.message || 'Fehler beim Speichern des Satzungstextes'
|
||||||
|
message.value = errMsg
|
||||||
|
messageType.value = 'error'
|
||||||
|
try {
|
||||||
|
window.showErrorModal && window.showErrorModal('Fehler', errMsg)
|
||||||
|
} catch {
|
||||||
|
// optional
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
savingText.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(loadCurrentSatzung)
|
onMounted(loadCurrentSatzung)
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user