Add WYSIWYG text editor for Satzung content management
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:
Torsten Schulz (local)
2026-02-06 12:57:51 +01:00
parent 717fdf3025
commit cc92615333

View File

@@ -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>