Files
2026-04-10 14:40:11 +07:00

120 lines
2.6 KiB
Vue

<script setup lang="ts">
import { computed } from 'vue';
type DialogLocation =
| 'top'
| 'bottom'
| 'left'
| 'right'
| 'start'
| 'end'
| 'center';
const props = withDefaults(
defineProps<{
modelValue: boolean;
maxWidth?: string | number;
persistent?: boolean;
transition?: string;
location?: DialogLocation;
scrollable?: boolean;
contentClass?: string;
}>(),
{
maxWidth: 600,
persistent: true,
transition: 'app-right-slide-transition',
location: 'right',
scrollable: true,
contentClass: '',
},
);
const emit = defineEmits<{
(e: 'update:modelValue', value: boolean): void;
}>();
const model = computed({
get: () => props.modelValue,
set: (value: boolean) => emit('update:modelValue', value),
});
const dialogContentClass = computed(() => {
const base = 'app-right-dialog';
return props.contentClass ? `${base} ${props.contentClass}` : base;
});
</script>
<template>
<v-dialog
v-model="model"
:max-width="props.maxWidth"
:persistent="props.persistent"
:transition="props.transition"
:location="props.location"
:scrollable="props.scrollable"
:content-class="dialogContentClass"
>
<slot />
</v-dialog>
</template>
<style>
/*
Ensures the dialog behaves like a right-side panel:
- pinned to the right
- full viewport height
- no default margins
*/
.app-right-dialog {
height: 100vh !important;
max-height: 100vh !important;
margin: 0 !important;
top: 0 !important;
right: 0 !important;
left: auto !important;
align-self: stretch;
border-radius: 0 !important;
}
.app-right-dialog .v-dialog {
height: 100%;
max-height: 100%;
margin: 0;
}
.app-right-dialog .v-card {
height: 100%;
max-height: 100%;
border-radius: 0 !important;
}
/* Vuetify surfaces sometimes wrap card/sheet */
.app-right-dialog .v-sheet {
border-radius: 0 !important;
}
/*
Custom transition for v-dialog content:
Slide in from right, slide out to right.
No fade-in / fade-out.
*/
.app-right-slide-transition-enter-active,
.app-right-slide-transition-leave-active {
transition: transform 240ms ease;
opacity: 1 !important;
}
.app-right-slide-transition-enter-from,
.app-right-slide-transition-leave-to {
transform: translateX(100%);
opacity: 1 !important;
}
.app-right-slide-transition-enter-to,
.app-right-slide-transition-leave-from {
transform: translateX(0%);
opacity: 1 !important;
}
</style>