feat: pure dialog (non-bloat) component

This commit is contained in:
Methapon2001 2024-08-07 17:56:06 +07:00
parent 301dcc32aa
commit 779374b164
3 changed files with 135 additions and 0 deletions

View file

@ -0,0 +1,83 @@
<script setup lang="ts">
const props = defineProps<{
width?: string;
height?: string;
maxWidth?: string;
footer?: boolean;
// Cannot emit as it cannot control when user wanted to interrupt close state (e.g. remain open)
onClose?: (fn: (state?: boolean) => void, ...args: unknown[]) => void;
onOpen?: (fn: (state?: boolean) => void, ...args: unknown[]) => void;
}>();
function update(value: boolean) {
if (value === false) {
if (props.onClose) {
props.onClose((v) => (state.value = v === undefined ? false : v));
} else {
state.value = false;
}
}
}
const state = defineModel({ default: false });
</script>
<template>
<q-dialog
:model-value="state"
@update:model-value="update"
@before-show="() => onOpen?.((v) => (state = v === undefined ? true : v))"
>
<div
class="surface-1 rounded"
:style="{
borderRadius: 'var(--radius-2)',
padding: '0',
width: $q.screen.xs ? '100%' : width ? width : '85%',
height: height ? height : 'calc(100vh - 64px)',
maxWidth: $q.screen.xs ? '100%' : maxWidth ? maxWidth : '85%',
}"
>
<div class="column full-height">
<!-- NOTE: DIALOG HEADER -->
<div class="form-header q-py-sm q-px-lg">
<slot name="header" />
</div>
<!-- NOTE: DIALOG BODY -->
<div
class="col full-height column full-width"
:class="{ dark: $q.dark.isActive }"
>
<slot />
</div>
<!-- NOTE: DIALOG FOOTER -->
<div
v-if="footer || $slots.footer"
class="dialog-footer row items-center full-width justify-between q-px-md q-py-md surface-1"
>
<slot name="footer"></slot>
</div>
</div>
</div>
</q-dialog>
</template>
<style scoped lang="scss">
.form-header {
border-bottom: 1px solid var(--border-color);
}
.dialog-body {
flex: 1;
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
}
.dialog-footer {
border-top: 1px solid var(--border-color);
}
</style>

View file

@ -0,0 +1,50 @@
<script lang="ts" setup>
defineProps<{
title: string;
}>();
</script>
<template>
<div class="dialog-header-container">
<div class="dialog-header-main">
<slot name="title-before" />
{{ title }}
<slot name="title-after" />
</div>
<q-btn
round
flat
unelevated
icon="mdi-close"
padding="xs"
class="dialog-header-close"
:class="{ dark: $q.dark.isActive }"
v-close-popup
>
<q-tooltip>{{ $t('close') }}</q-tooltip>
</q-btn>
</div>
</template>
<style scoped>
.dialog-header-container {
display: flex;
align-items: center;
}
.dialog-header-main {
flex: 1;
text-align: center;
font-weight: bolder;
}
.dialog-header-close {
color: hsl(var(--negative-bg));
margin-left: auto;
&.dark {
background-color: transparent;
border: 1px solid hsl(var(--negative-bg));
}
}
</style>

View file

@ -0,0 +1,2 @@
export { default as DialogContainer } from './DialogContainer.vue';
export { default as DialogHeader } from './DialogHeader.vue';