This commit is contained in:
Viet An
2026-05-14 20:49:28 +07:00
parent 400bbf242e
commit 4b67a9f160
5 changed files with 70 additions and 84 deletions

View File

@@ -1,9 +1,9 @@
<template> <template>
<div class="field is-grouped is-gap-1"> <div class="is-flex is-align-items-center is-gap-1">
<Icon <Icon
name="material-symbols:cancel-rounded" name="material-symbols:cancel-rounded"
:size="22" :size="22"
class="has-text-danger-70" class="has-text-danger-80"
/> />
<p <p
v-html="content" v-html="content"

View File

@@ -1,10 +1,23 @@
<template> <template>
<div class="snackbar has-text-white has-background-grey-35 px-3 py-2 rounded-md"> <div
class="snackbar is-flex is-align-items-center is-gap-3 pl-3 pr-1.5 py-2 rounded-md has-background-grey-35 has-text-white"
>
<component <component
:is="dynamicComponent" :is="resolvedComponent"
v-bind="vbind" v-bind="vbind"
@close="$emit('close')" @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> </div>
</template> </template>
<script setup> <script setup>
@@ -19,7 +32,30 @@ const props = defineProps({
}); });
const store = useStore(); const store = useStore();
const dynamicComponent = defineAsyncComponent(() => import(`../snackbar/${props.component || "Info"}.vue`)); 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); setTimeout(() => store.commit("snackbar", undefined), 3900);
</script> </script>
<style scoped> <style scoped>
@@ -32,59 +68,13 @@ setTimeout(() => store.commit("snackbar", undefined), 3900);
margin-inline: auto; margin-inline: auto;
width: fit-content; width: fit-content;
max-width: 500px; max-width: 500px;
/* Add animation: Take 0.5 seconds to fade in and out the snackbar.
However, delay the fade out process for 2.5 seconds */
-webkit-animation:
fadein 0.5s,
fadeout 0.5s 3.5s;
animation:
fadein 0.5s,
fadeout 0.5s 3.5s;
} }
/* Animations to fade the snackbar in and out */ .button.is-ghost {
@-webkit-keyframes fadein { color: white;
from {
top: 0;
opacity: 0;
}
to {
top: 50px;
opacity: 1;
}
}
@keyframes fadein {
from {
top: 0;
opacity: 0;
}
to {
top: 50px;
opacity: 1;
}
}
@-webkit-keyframes fadeout {
from {
top: 50px;
opacity: 1;
}
to {
top: 0;
opacity: 0;
}
}
@keyframes fadeout {
from {
top: 50px;
opacity: 1;
}
to {
top: 0;
opacity: 0;
} }
.button.is-ghost:hover,
.button.is-ghost.is-hovered {
color: hsl(0, 0%, 100%, 0.6);
} }
</style> </style>

View File

@@ -1,9 +1,9 @@
<template> <template>
<div class="field is-grouped is-gap-1"> <div class="is-flex is-align-items-center is-gap-1">
<Icon <Icon
name="material-symbols:check-circle-rounded" name="material-symbols:check-circle-rounded"
:size="22" :size="22"
class="has-text-success" class="has-text-success-70"
/> />
<p <p
v-html="content" v-html="content"

View File

@@ -4,14 +4,16 @@
lang="vi" lang="vi"
> >
<slot></slot> <slot></slot>
<Transition>
<SnackBar <SnackBar
v-if="snackbar" v-if="$store.snackbar"
v-bind="snackbar" v-bind="$store.snackbar"
@close="$store.removeSnackbar()" @close="$store.snackbar = undefined"
/> />
</Transition>
<Modal <Modal
v-bind="showmodal" v-bind="$store.showmodal"
@close="showmodal = undefined" @close="$store.showmodal = undefined"
/> />
<!-- <Modal2 <!-- <Modal2
v-for="modal in modals" v-for="modal in modals"
@@ -31,8 +33,6 @@ import { throttle } from "es-toolkit";
const route = useRoute(); const route = useRoute();
const { $getdata, $requestLogin, $store } = useNuxtApp(); const { $getdata, $requestLogin, $store } = useNuxtApp();
const authorized = ref(false); const authorized = ref(false);
const snackbar = ref(undefined);
const showmodal = ref(undefined);
function getViewport() { function getViewport() {
let viewport; let viewport;
@@ -90,17 +90,17 @@ onMounted(() => {
const throttledGetViewport = throttle(getViewport, 400); const throttledGetViewport = throttle(getViewport, 400);
window.addEventListener("resize", throttledGetViewport); window.addEventListener("resize", throttledGetViewport);
}); });
watch(
() => $store.snackbar,
(newVal) => {
snackbar.value = newVal;
},
{ deep: true },
);
watch(
() => $store.showmodal,
(newVal) => {
showmodal.value = newVal;
},
);
</script> </script>
<style lang="css" scoped>
.v-enter-active,
.v-leave-active {
transition: all 0.3s ease;
}
.v-enter-from,
.v-leave-to {
opacity: 0;
top: 0;
}
</style>

View File

@@ -24,10 +24,6 @@ export const useStore = defineStore("maindev", {
this[name] = data; this[name] = data;
}, },
removeSnackbar() {
this.snackbar = undefined;
},
updateProduct(products) { updateProduct(products) {
this.product = products; this.product = products;
}, },