funkwhale/front/src/components/ui/Modal.vue

81 lines
2.1 KiB
Vue

<script setup lang="ts">
import { type ColorProps, type DefaultProps, color } from '~/composables/color';
import { watchEffect } from 'vue';
import onKeyboardShortcut from '~/composables/onKeyboardShortcut';
import Button from '~/components/ui/Button.vue'
import Spacer from '~/components/ui/Spacer.vue'
import Layout from '~/components/ui/Layout.vue'
const props = defineProps<{
title: string,
overPopover?: true,
destructive?: true
} & (ColorProps | DefaultProps)>()
const isOpen = defineModel<boolean>({ default:false })
watchEffect(() =>
isOpen.value
? document.querySelector('#app')?.setAttribute('inert', 'true')
: document.querySelector('#app')?.removeAttribute('inert')
)
onKeyboardShortcut('escape', () => isOpen.value = false)
// TODO:
// When overflowing content: Add inset shadow to indicate scrollability
// - [ ] Add aria role to inform screenreaders
</script>
<template>
<Teleport to="body">
<Transition mode="out-in">
<div v-if="isOpen"
@click.exact.stop="isOpen = false"
class="funkwhale overlay"
>
<div @click.stop
class="funkwhale modal"
:class="[
{ 'is-destructive': destructive,
'has-alert': !!$slots.alert,
'over-popover': overPopover,
}
]"
v-bind="color(props)"
>
<h2
:class="{
'destructive-header': destructive
}"
>
{{ title }}
<Button icon="bi-x-lg" ghost @click="isOpen = false" />
</h2>
<div class="modal-content">
<Transition>
<div v-if="$slots.alert" class="alert-container">
<div>
<slot name="alert" />
</div>
</div>
</Transition>
<slot />
</div>
<Layout flex gap-12 style="flex-wrap: wrap;" v-if="$slots.actions" class="modal-actions">
<slot name="actions" />
</Layout>
<Spacer :size="64" v-else />
</div>
</div>
</Transition>
</Teleport>
</template>
<style lang="scss">
@import './modal.scss'
</style>