120 lines
2.6 KiB
Vue
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>
|