Operation processes on invoices
This commit is contained in:
146
app/Views/Components/FullScreenModal.vue
Normal file
146
app/Views/Components/FullScreenModal.vue
Normal file
@@ -0,0 +1,146 @@
|
||||
<template>
|
||||
<teleport to="body">
|
||||
<transition name="fade">
|
||||
<div
|
||||
v-if="show"
|
||||
class="full-screen-modal-overlay"
|
||||
@click.self="close"
|
||||
>
|
||||
<transition name="scale">
|
||||
<div
|
||||
v-if="show"
|
||||
ref="modalRef"
|
||||
class="full-screen-modal-content"
|
||||
tabindex="-1"
|
||||
>
|
||||
<div class="full-screen-modal-body">
|
||||
<slot />
|
||||
<span @click="close" class="dashicons dashicons-dismiss full-screen-modal-close"></span>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</transition>
|
||||
</teleport>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch, onMounted, onUnmounted, nextTick } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
show: Boolean
|
||||
})
|
||||
const emit = defineEmits(['close'])
|
||||
|
||||
const modalRef = ref(null)
|
||||
|
||||
function close() {
|
||||
emit('close')
|
||||
}
|
||||
|
||||
// ESC-Key & Focus-Trap
|
||||
function handleKeyDown(e) {
|
||||
if (e.key === 'Escape') {
|
||||
close()
|
||||
}
|
||||
if (e.key === 'Tab' && modalRef.value) {
|
||||
const focusable = modalRef.value.querySelectorAll(
|
||||
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
|
||||
)
|
||||
if (focusable.length === 0) return
|
||||
|
||||
const first = focusable[0]
|
||||
const last = focusable[focusable.length - 1]
|
||||
|
||||
if (e.shiftKey && document.activeElement === first) {
|
||||
e.preventDefault()
|
||||
last.focus()
|
||||
} else if (!e.shiftKey && document.activeElement === last) {
|
||||
e.preventDefault()
|
||||
first.focus()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Body-Scroll sperren
|
||||
watch(
|
||||
() => props.show,
|
||||
async (newVal) => {
|
||||
if (newVal) {
|
||||
document.body.style.overflow = 'hidden'
|
||||
await nextTick()
|
||||
modalRef.value?.focus()
|
||||
} else {
|
||||
document.body.style.overflow = ''
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener('keydown', handleKeyDown)
|
||||
})
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('keydown', handleKeyDown)
|
||||
document.body.style.overflow = ''
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.full-screen-modal-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.full-screen-modal-content {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
position: absolute;
|
||||
top: 30px;
|
||||
bottom: 30px;
|
||||
left: 30px;
|
||||
right: 30px;
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
|
||||
outline: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.full-screen-modal-body {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 20px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.full-screen-modal-close {
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
right: 15px;
|
||||
cursor: pointer;
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
/* Animation */
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
.scale-enter-active,
|
||||
.scale-leave-active {
|
||||
transition: transform 0.25s ease, opacity 0.25s ease;
|
||||
}
|
||||
.scale-enter-from,
|
||||
.scale-leave-to {
|
||||
transform: scale(0.98);
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user