- Introduced new Vue components for homepage teasers: HomeLinksTeaser, HomeSpielplanTeamWidget, HomeTrainingTeaser, and HomeVereinsmeisterschaftenTeaser. - Created XML layout for tablet app window dump. - Implemented API endpoints for fetching and updating homepage settings. - Added API for retrieving spielplan options, including team extraction logic.
188 lines
5.3 KiB
Vue
188 lines
5.3 KiB
Vue
<template>
|
|
<!-- Success Toast (bottom) -->
|
|
<div
|
|
v-if="showSuccessToast"
|
|
class="fixed left-0 right-0 mx-auto max-w-3xl z-50 pointer-events-none"
|
|
style="bottom:72px;"
|
|
>
|
|
<div class="pointer-events-auto mx-4 shadow-lg rounded-md overflow-hidden">
|
|
<div class="px-4 py-3 bg-green-50 text-green-800 text-sm">
|
|
<div class="font-medium">
|
|
{{ toastTitle }}
|
|
</div>
|
|
<div class="mt-1">
|
|
{{ toastMessage }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Error Modal -->
|
|
<div
|
|
v-if="showError"
|
|
class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4"
|
|
@click.self="closeError"
|
|
>
|
|
<div class="bg-white rounded-lg max-w-md w-full p-6">
|
|
<div class="flex items-center mb-4">
|
|
<div class="flex-shrink-0 w-10 h-10 mx-auto bg-red-100 rounded-full flex items-center justify-center">
|
|
<svg
|
|
class="w-6 h-6 text-red-600"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
viewBox="0 0 24 24"
|
|
>
|
|
<path
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
stroke-width="2"
|
|
d="M6 18L18 6M6 6l12 12"
|
|
/>
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
<div class="text-center">
|
|
<h3 class="text-lg font-medium text-gray-900 mb-2">
|
|
{{ errorTitle }}
|
|
</h3>
|
|
<p class="text-sm text-gray-600 mb-6">
|
|
{{ errorMessage }}
|
|
</p>
|
|
<div class="flex justify-center">
|
|
<button
|
|
class="px-6 py-2 bg-red-600 hover:bg-red-700 text-white rounded-lg transition-colors"
|
|
@click="closeError"
|
|
>
|
|
OK
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Confirm Modal -->
|
|
<div
|
|
v-if="showConfirm"
|
|
class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4"
|
|
@click.self="closeConfirm"
|
|
>
|
|
<div class="bg-white rounded-lg max-w-md w-full p-6">
|
|
<div class="flex items-center mb-4">
|
|
<div class="flex-shrink-0 w-10 h-10 mx-auto bg-yellow-100 rounded-full flex items-center justify-center">
|
|
<svg
|
|
class="w-6 h-6 text-yellow-600"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
viewBox="0 0 24 24"
|
|
>
|
|
<path
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
stroke-width="2"
|
|
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"
|
|
/>
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
<div class="text-center">
|
|
<h3 class="text-lg font-medium text-gray-900 mb-2">
|
|
{{ confirmTitle }}
|
|
</h3>
|
|
<p class="text-sm text-gray-600 mb-6">
|
|
{{ confirmMessage }}
|
|
</p>
|
|
<div class="flex space-x-3 justify-center">
|
|
<button
|
|
class="px-4 py-2 text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors"
|
|
@click="closeConfirm"
|
|
>
|
|
Abbrechen
|
|
</button>
|
|
<button
|
|
class="px-4 py-2 bg-red-600 hover:bg-red-700 text-white rounded-lg transition-colors"
|
|
@click="executeConfirm"
|
|
>
|
|
Bestätigen
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref } from 'vue'
|
|
|
|
// Modal / Toast States
|
|
const showSuccessToast = ref(false)
|
|
const showError = ref(false)
|
|
const showConfirm = ref(false)
|
|
|
|
// Modal / Toast Content
|
|
const toastTitle = ref('')
|
|
const toastMessage = ref('')
|
|
const errorTitle = ref('')
|
|
const errorMessage = ref('')
|
|
const confirmTitle = ref('')
|
|
const confirmMessage = ref('')
|
|
const confirmAction = ref(null)
|
|
|
|
// Modal Functions
|
|
let toastTimeout = null
|
|
const showSuccessModal = (title, message) => {
|
|
// Show non-blocking toast at bottom instead of modal dialog
|
|
toastTitle.value = title || 'Erfolg'
|
|
toastMessage.value = message || ''
|
|
showSuccessToast.value = true
|
|
if (toastTimeout) clearTimeout(toastTimeout)
|
|
toastTimeout = setTimeout(() => { showSuccessToast.value = false; toastTimeout = null }, 3500)
|
|
}
|
|
|
|
const showErrorModal = (title, message) => {
|
|
errorTitle.value = title
|
|
errorMessage.value = message
|
|
showError.value = true
|
|
}
|
|
|
|
const showConfirmModal = (title, message, action) => {
|
|
confirmTitle.value = title
|
|
confirmMessage.value = message
|
|
confirmAction.value = action
|
|
showConfirm.value = true
|
|
}
|
|
|
|
const closeSuccess = () => {
|
|
showSuccessToast.value = false
|
|
if (toastTimeout) { clearTimeout(toastTimeout); toastTimeout = null }
|
|
}
|
|
|
|
const closeError = () => {
|
|
showError.value = false
|
|
}
|
|
|
|
const closeConfirm = () => {
|
|
showConfirm.value = false
|
|
confirmAction.value = null
|
|
}
|
|
|
|
const executeConfirm = async () => {
|
|
showConfirm.value = false
|
|
if (confirmAction.value) {
|
|
await confirmAction.value()
|
|
}
|
|
confirmAction.value = null
|
|
}
|
|
|
|
// Expose functions globally
|
|
provide('showSuccessModal', showSuccessModal)
|
|
provide('showErrorModal', showErrorModal)
|
|
provide('showConfirmModal', showConfirmModal)
|
|
|
|
// Also expose on window for vanilla JS usage
|
|
if (typeof window !== 'undefined') {
|
|
window.showSuccessModal = showSuccessModal
|
|
window.showErrorModal = showErrorModal
|
|
window.showConfirmModal = showConfirmModal
|
|
}
|
|
</script>
|