81 lines
1.8 KiB
Vue
81 lines
1.8 KiB
Vue
<template>
|
|
<div
|
|
class="snackbar is-flex is-align-items-center is-gap-3 pl-3 pr-1.5 py-2 rounded-md has-background-grey-25 has-text-white"
|
|
>
|
|
<component
|
|
:is="resolvedComponent"
|
|
v-bind="vbind"
|
|
@close="$emit('close')"
|
|
/>
|
|
<button
|
|
@click="$emit('close')"
|
|
class="button is-ghost is-small"
|
|
>
|
|
<span class="icon">
|
|
<Icon
|
|
name="material-symbols:close-rounded"
|
|
:size="18"
|
|
/>
|
|
</span>
|
|
</button>
|
|
</div>
|
|
</template>
|
|
<script setup>
|
|
import { defineAsyncComponent } from "vue";
|
|
import { useStore } from "@/stores/index";
|
|
const props = defineProps({
|
|
component: String,
|
|
width: String,
|
|
height: String,
|
|
vbind: Object,
|
|
title: String,
|
|
});
|
|
|
|
const store = useStore();
|
|
const componentFiles = import.meta.glob("@/components/**/*.vue");
|
|
const resolvedComponent = shallowRef(null);
|
|
|
|
function loadDynamicComponent() {
|
|
if (!props.component) {
|
|
resolvedComponent.value = null;
|
|
return;
|
|
}
|
|
|
|
const fullPath = `/components/snackbar/${props.component}.vue`;
|
|
const componentPath = Object.keys(componentFiles).find((path) => path.endsWith(fullPath));
|
|
|
|
if (componentPath) {
|
|
resolvedComponent.value = defineAsyncComponent(componentFiles[componentPath]);
|
|
} else {
|
|
console.error(`Không tìm thấy component tại: ${fullPath}`);
|
|
resolvedComponent.value = null;
|
|
}
|
|
}
|
|
|
|
// Theo dõi sự thay đổi của props.component để load lại nếu cần
|
|
watchEffect(() => {
|
|
loadDynamicComponent();
|
|
});
|
|
setTimeout(() => store.commit("snackbar", undefined), 3900);
|
|
</script>
|
|
<style scoped>
|
|
.snackbar {
|
|
position: fixed;
|
|
z-index: 999;
|
|
top: 50px;
|
|
left: 0;
|
|
right: 0;
|
|
margin-inline: auto;
|
|
width: fit-content;
|
|
max-width: 500px;
|
|
}
|
|
|
|
.button.is-ghost {
|
|
color: white;
|
|
}
|
|
.button.is-ghost:hover,
|
|
.button.is-ghost.is-hovered {
|
|
color: hsl(0, 0%, 100%, 0.6);
|
|
}
|
|
</style>
|