diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 0710829..f6f3801 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -14,6 +14,7 @@
"clipboard": "^2.0.11",
"core-js": "^3.37.1",
"moment": "^2.30.1",
+ "notivue": "^2.4.4",
"pinia": "^2.1.7",
"qrcode.vue": "^3.4.1",
"roboto-fontface": "^0.10.0",
@@ -2522,6 +2523,28 @@
"node": ">=0.10.0"
}
},
+ "node_modules/notivue": {
+ "version": "2.4.4",
+ "resolved": "https://registry.npmjs.org/notivue/-/notivue-2.4.4.tgz",
+ "integrity": "sha512-d9RaXMbSQD1DS0rrA5WCfql2xm5nXOq1U1nnf8bgQ1LRHu4UsLY57Bdc9O9SHTpR1gDmm/pSxq7gocitzDtMpw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@nuxt/kit": ">=3.5.0",
+ "@nuxt/schema": ">=3.5.0",
+ "defu": ">=6"
+ },
+ "peerDependenciesMeta": {
+ "@nuxt/kit": {
+ "optional": true
+ },
+ "@nuxt/schema": {
+ "optional": true
+ },
+ "defu": {
+ "optional": true
+ }
+ }
+ },
"node_modules/nth-check": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index d981dae..f37f635 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -15,6 +15,7 @@
"clipboard": "^2.0.11",
"core-js": "^3.37.1",
"moment": "^2.30.1",
+ "notivue": "^2.4.4",
"pinia": "^2.1.7",
"qrcode.vue": "^3.4.1",
"roboto-fontface": "^0.10.0",
diff --git a/frontend/src/components/message.vue b/frontend/src/components/message.vue
index d464072..33c0db4 100644
--- a/frontend/src/components/message.vue
+++ b/frontend/src/components/message.vue
@@ -1,18 +1,38 @@
-
- {{ snackbar.message }}
-
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/src/layouts/modals/QrCode.vue b/frontend/src/layouts/modals/QrCode.vue
index a8be6da..f5a977a 100644
--- a/frontend/src/layouts/modals/QrCode.vue
+++ b/frontend/src/layouts/modals/QrCode.vue
@@ -5,7 +5,7 @@
QrCode
-
+
@@ -31,14 +31,13 @@
import QrcodeVue from 'qrcode.vue'
import Data from '@/store/modules/data'
import Clipboard from 'clipboard'
-import Message from '@/store/modules/message'
import { i18n } from '@/locales'
+import { push } from 'notivue'
export default {
props: ['index'],
data() {
return {
- msg: Message(),
}
},
methods: {
@@ -54,12 +53,18 @@ export default {
clipboard.on('success', () => {
clipboard.destroy()
- this.msg.showMessage(i18n.global.t('copyToClipboard') + " : " + i18n.global.t('success'),'success',5000)
+ push.success({
+ message: i18n.global.t('success') + ": " + i18n.global.t('copyToClipboard'),
+ duration: 5000,
+ })
})
clipboard.on('error', () => {
clipboard.destroy()
- this.msg.showMessage(i18n.global.t('copyToClipboard') + " : " + i18n.global.t('failed'),'error',5000)
+ push.error({
+ message: i18n.global.t('failed') + ": " + i18n.global.t('copyToClipboard'),
+ duration: 5000,
+ })
})
// Perform click on hidden button to trigger copy
diff --git a/frontend/src/locales/en.ts b/frontend/src/locales/en.ts
index 0d176f6..74ba095 100644
--- a/frontend/src/locales/en.ts
+++ b/frontend/src/locales/en.ts
@@ -26,6 +26,7 @@ export default {
count: "Count",
error: {
dplData: "Duplicate Data",
+ core: "Sing-Box Error",
},
pages: {
login: "Login",
diff --git a/frontend/src/locales/fa.ts b/frontend/src/locales/fa.ts
index 3d661d9..a7da434 100644
--- a/frontend/src/locales/fa.ts
+++ b/frontend/src/locales/fa.ts
@@ -26,6 +26,7 @@ export default {
count: "تعداد",
error: {
dplData: "داده تکراری",
+ core: "خطا در سینگباکس",
},
pages: {
login: "ورود",
diff --git a/frontend/src/locales/vi.ts b/frontend/src/locales/vi.ts
index fc42d1f..d16699c 100644
--- a/frontend/src/locales/vi.ts
+++ b/frontend/src/locales/vi.ts
@@ -26,6 +26,7 @@ export default {
count: "Đếm",
error: {
dplData: "Dữ liệu trùng lặp",
+ core: "Lỗi Sing-Box",
},
pages: {
login: "Đăng nhập",
diff --git a/frontend/src/locales/zhcn.ts b/frontend/src/locales/zhcn.ts
index 4d9b870..e645994 100644
--- a/frontend/src/locales/zhcn.ts
+++ b/frontend/src/locales/zhcn.ts
@@ -26,6 +26,7 @@ export default {
count: "计数",
error: {
dplData: "重复数据",
+ core: "Sing-Box 错误",
},
pages: {
login: "登录",
diff --git a/frontend/src/locales/zhtw.ts b/frontend/src/locales/zhtw.ts
index 3175b1c..1e25138 100644
--- a/frontend/src/locales/zhtw.ts
+++ b/frontend/src/locales/zhtw.ts
@@ -27,6 +27,7 @@ export default {
count: "計數",
error: {
dplData: "重複數據",
+ core: "Sing-Box 錯誤",
},
pages: {
login: "登錄",
diff --git a/frontend/src/main.ts b/frontend/src/main.ts
index 72c28fc..b96eaa7 100644
--- a/frontend/src/main.ts
+++ b/frontend/src/main.ts
@@ -23,6 +23,22 @@ import { registerPlugins } from '@/plugins'
import { i18n } from '@/locales'
import Vue3PersianDatetimePicker from 'vue3-persian-datetime-picker'
+// Notivue
+import { createNotivue } from 'notivue'
+import 'notivue/notification.css'
+import 'notivue/animations.css'
+const notivue = createNotivue({
+ position: 'top-center',
+ limit: 4,
+ enqueue: false,
+ avoidDuplicates: false,
+ notifications: {
+ global: {
+ duration: 3000
+ }
+ },
+})
+
const loading = ref(false)
const app = createApp(App)
@@ -34,5 +50,6 @@ app
.use(router)
.use(store)
.use(i18n)
+ .use(notivue)
.component('DatePicker', Vue3PersianDatetimePicker)
.mount('#app')
diff --git a/frontend/src/plugins/httputil.ts b/frontend/src/plugins/httputil.ts
index 0b43aac..9aa7ca9 100644
--- a/frontend/src/plugins/httputil.ts
+++ b/frontend/src/plugins/httputil.ts
@@ -1,7 +1,7 @@
import api from './api'
import { i18n } from '@/locales'
import router from '@/router'
-import Message from "@/store/modules/message"
+import { push } from 'notivue'
export interface Msg {
success: boolean
@@ -10,18 +10,27 @@ export interface Msg {
}
function _handleMsg(msg: any): void {
- const sb = Message()
if (!isMsg(msg)) {
return
}
if(msg.msg){
if (!msg.success && msg.msg == "Invalid login") {
- sb.showMessage(i18n.global.t('invalidLogin'),'error', 5000)
+ push.error({
+ title: i18n.global.t('invalidLogin'),
+ })
logout()
return
}
- const message = msg.success ? i18n.global.t('success') + ": " + i18n.global.t('actions.' + msg.msg) : i18n.global.t('failed') + ": " + msg.msg
- sb.showMessage(message, msg.success ? 'success' : 'error', 5000)
+ if (msg.success) {
+ push.success({
+ message: i18n.global.t('success') + ": " + i18n.global.t('actions.' + msg.msg),
+ })
+ } else {
+ push.error({
+ title: i18n.global.t('failed'),
+ message: msg.msg
+ })
+ }
}
}
diff --git a/frontend/src/store/modules/data.ts b/frontend/src/store/modules/data.ts
index 0f523a3..654e0d0 100644
--- a/frontend/src/store/modules/data.ts
+++ b/frontend/src/store/modules/data.ts
@@ -1,7 +1,8 @@
import { FindDiff } from '@/plugins/utils'
import HttpUtils from '@/plugins/httputil'
import { defineStore } from 'pinia'
-import Message from './message'
+import { push } from 'notivue'
+import { i18n } from '@/locales'
const Data = defineStore('Data', {
state: () => ({
@@ -26,8 +27,11 @@ const Data = defineStore('Data', {
if (msg.obj.tls) this.oldData.tlsConfigs = msg.obj.tls
this.onlines = msg.obj.onlines
if (msg.obj.lastLog) {
- const sb = Message()
- sb.showMessage('Core error: \n' + msg.obj.lastLog,'error', 5000)
+ push.error({
+ title: i18n.global.t('error.core'),
+ duration: 5000,
+ message: msg.obj.lastLog
+ })
}
if (msg.obj.config) {
diff --git a/frontend/src/store/modules/message.ts b/frontend/src/store/modules/message.ts
deleted file mode 100644
index 22dc957..0000000
--- a/frontend/src/store/modules/message.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import { defineStore } from 'pinia'
-
-const Message = defineStore('msg', {
- state: () => ({
- showMsg: false,
- snackbar: {
- message: '',
- timeout: 5000,
- color: '',
- }
- }),
- actions: {
- showMessage(message:string, color='success',timeout=5000) {
- this.snackbar.message = message
- this.snackbar.color = color
- this.snackbar.timeout = timeout
- this.showMsg = true
- }
- },
-})
-
-export default Message
\ No newline at end of file
diff --git a/frontend/src/views/Clients.vue b/frontend/src/views/Clients.vue
index f687f0e..f147ddb 100644
--- a/frontend/src/views/Clients.vue
+++ b/frontend/src/views/Clients.vue
@@ -135,8 +135,8 @@ import { Config, V2rayApiStats } from '@/types/config'
import { InTypes, Inbound,InboundWithUser, ShadowTLS, VLESS } from '@/types/inbounds'
import { Link, LinkUtil } from '@/plugins/link'
import { HumanReadable } from '@/plugins/utils'
-import Message from '@/store/modules/message'
import { i18n } from '@/locales'
+import { push } from 'notivue'
const clients = computed((): any[] => {
return Data().clients
@@ -185,8 +185,9 @@ const saveModal = (data:any, stats:boolean) => {
// Check duplicate name
const oldName = modal.value.index != -1 ? clients.value[modal.value.index].name : null
if (data.name != oldName && clients.value.findIndex(c => c.name == data.name) != -1) {
- const sb = Message()
- sb.showMessage(i18n.global.t('error.dplData') + ': ' + i18n.global.t('client.name') ,'error', 5000)
+ push.error({
+ message: i18n.global.t('error.dplData') + ": " + i18n.global.t('client.name')
+ })
return
}
if(modal.value.index == -1) {
diff --git a/frontend/src/views/Inbounds.vue b/frontend/src/views/Inbounds.vue
index a0f5c40..7c16fa1 100644
--- a/frontend/src/views/Inbounds.vue
+++ b/frontend/src/views/Inbounds.vue
@@ -109,8 +109,8 @@ import { computed, ref } from 'vue'
import { InTypes, Inbound, InboundWithUser, ShadowTLS, VLESS } from '@/types/inbounds'
import { Client } from '@/types/clients'
import { Link, LinkUtil } from '@/plugins/link'
-import Message from '@/store/modules/message'
import { i18n } from '@/locales'
+import { push } from 'notivue'
const appConfig = computed((): Config => {
return Data().config
@@ -166,8 +166,9 @@ const saveModal = (data:Inbound, stats: boolean, tls_id: number) => {
// Check duplicate tag
const oldTag = modal.value.id != -1 ? inbounds.value[modal.value.id].tag : null
if (data.tag != oldTag && inTags.value.includes(data.tag)) {
- const sb = Message()
- sb.showMessage(i18n.global.t('error.dplData') + ': ' + i18n.global.t('objects.tag') ,'error', 5000)
+ push.error({
+ message: i18n.global.t('error.dplData') + ": " + i18n.global.t('objects.tag')
+ })
return
}
diff --git a/frontend/src/views/Outbounds.vue b/frontend/src/views/Outbounds.vue
index 2472c04..2b50949 100644
--- a/frontend/src/views/Outbounds.vue
+++ b/frontend/src/views/Outbounds.vue
@@ -96,8 +96,8 @@ import Stats from '@/layouts/modals/Stats.vue'
import { Config, V2rayApiStats } from '@/types/config';
import { Outbound } from '@/types/outbounds';
import { computed, ref } from 'vue'
-import Message from '@/store/modules/message';
import { i18n } from '@/locales';
+import { push } from 'notivue';
const appConfig = computed((): Config => {
return Data().config
@@ -142,8 +142,9 @@ const saveModal = (data:Outbound, stats: boolean) => {
// Check duplicate tag
const oldTag = modal.value.id != -1 ? outbounds.value[modal.value.id].tag : null
if (data.tag != oldTag && outboundTags.value.includes(data.tag)) {
- const sb = Message()
- sb.showMessage(i18n.global.t('error.dplData') + ': ' + i18n.global.t('objects.tag') ,'error', 5000)
+ push.error({
+ message: i18n.global.t('error.dplData') + ": " + i18n.global.t('objects.tag')
+ })
return
}
// New or Edit