Initialer Laravel Commit für BetiX
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (8.4) (push) Has been cancelled
tests / ci (8.5) (push) Has been cancelled

This commit is contained in:
2026-04-04 18:01:50 +02:00
commit 0280278978
374 changed files with 65210 additions and 0 deletions

View File

@@ -0,0 +1,104 @@
<script setup lang="ts">
import { ref, watch } from 'vue';
const props = defineProps<{
isOpen: boolean;
title: string;
message: string;
confirmText?: string;
cancelText?: string;
requireHold?: boolean; // If true, user must hold button for 3s
}>();
const emit = defineEmits(['close', 'confirm']);
const holdProgress = ref(0);
let holdInterval: number | undefined;
const startHold = () => {
if (!props.requireHold) return;
holdProgress.value = 0;
holdInterval = window.setInterval(() => {
holdProgress.value += 2; // 50 * 2 = 100% in ~2.5s (adjusted for UX)
if (holdProgress.value >= 100) {
stopHold();
emit('confirm');
}
}, 50); // Update every 50ms
};
const stopHold = () => {
if (holdInterval) {
clearInterval(holdInterval);
holdInterval = undefined;
}
if (holdProgress.value < 100) {
holdProgress.value = 0;
}
};
const onConfirmClick = () => {
if (!props.requireHold) {
emit('confirm');
}
};
watch(() => props.isOpen, (val) => {
if (!val) {
stopHold();
holdProgress.value = 0;
}
});
</script>
<template>
<transition name="fade">
<div v-if="isOpen" class="modal-overlay">
<div class="modal-card">
<div class="modal-head">{{ title }}</div>
<div class="modal-body">{{ message }}</div>
<div class="modal-actions">
<button class="btn-cancel" @click="$emit('close')">{{ cancelText || 'Cancel' }}</button>
<button
class="btn-confirm"
:class="{ 'holding': requireHold }"
@mousedown="startHold"
@mouseup="stopHold"
@mouseleave="stopHold"
@touchstart.prevent="startHold"
@touchend.prevent="stopHold"
@click="onConfirmClick"
>
<div v-if="requireHold" class="hold-fill" :style="{ width: `${holdProgress}%` }"></div>
<span class="btn-text">{{ confirmText || 'Confirm' }}</span>
<span v-if="requireHold && holdProgress > 0" class="hold-hint">Hold...</span>
</button>
</div>
</div>
</div>
</transition>
</template>
<style scoped>
.modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.8); backdrop-filter: blur(5px); z-index: 9999; display: flex; align-items: center; justify-content: center; }
.modal-card { background: #0a0a0a; border: 1px solid #222; border-radius: 16px; padding: 24px; width: 90%; max-width: 400px; box-shadow: 0 20px 50px rgba(0,0,0,0.8); animation: popIn 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); }
.modal-head { font-size: 16px; font-weight: 900; color: #fff; margin-bottom: 10px; text-transform: uppercase; letter-spacing: 1px; }
.modal-body { font-size: 13px; color: #bbb; margin-bottom: 24px; line-height: 1.5; }
.modal-actions { display: flex; gap: 12px; justify-content: flex-end; }
.btn-cancel { background: transparent; border: 1px solid #333; color: #888; padding: 10px 16px; border-radius: 8px; font-weight: 700; cursor: pointer; transition: 0.2s; }
.btn-cancel:hover { color: #fff; border-color: #555; }
.btn-confirm { background: #ff007a; border: none; color: #fff; padding: 10px 20px; border-radius: 8px; font-weight: 900; cursor: pointer; position: relative; overflow: hidden; transition: 0.2s; }
.btn-confirm:hover { box-shadow: 0 0 15px rgba(255,0,122,0.4); }
.btn-confirm.holding { background: #33001a; border: 1px solid #ff007a; }
.hold-fill { position: absolute; top: 0; left: 0; height: 100%; background: #ff007a; transition: width 0.05s linear; z-index: 0; }
.btn-text { position: relative; z-index: 1; }
.hold-hint { position: absolute; right: 10px; font-size: 9px; opacity: 0.7; z-index: 1; top: 50%; transform: translateY(-50%); }
@keyframes popIn { from { opacity: 0; transform: scale(0.9); } to { opacity: 1; transform: scale(1); } }
.fade-enter-active, .fade-leave-active { transition: opacity 0.2s; }
.fade-enter-from, .fade-leave-to { opacity: 0; }
</style>