change snackbar to nitivue

This commit is contained in:
Alireza Ahmadi
2024-06-09 22:48:32 +02:00
parent b5920cdc07
commit 3b24819309
16 changed files with 120 additions and 55 deletions
+23
View File
@@ -14,6 +14,7 @@
"clipboard": "^2.0.11", "clipboard": "^2.0.11",
"core-js": "^3.37.1", "core-js": "^3.37.1",
"moment": "^2.30.1", "moment": "^2.30.1",
"notivue": "^2.4.4",
"pinia": "^2.1.7", "pinia": "^2.1.7",
"qrcode.vue": "^3.4.1", "qrcode.vue": "^3.4.1",
"roboto-fontface": "^0.10.0", "roboto-fontface": "^0.10.0",
@@ -2522,6 +2523,28 @@
"node": ">=0.10.0" "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": { "node_modules/nth-check": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+1
View File
@@ -15,6 +15,7 @@
"clipboard": "^2.0.11", "clipboard": "^2.0.11",
"core-js": "^3.37.1", "core-js": "^3.37.1",
"moment": "^2.30.1", "moment": "^2.30.1",
"notivue": "^2.4.4",
"pinia": "^2.1.7", "pinia": "^2.1.7",
"qrcode.vue": "^3.4.1", "qrcode.vue": "^3.4.1",
"roboto-fontface": "^0.10.0", "roboto-fontface": "^0.10.0",
+31 -11
View File
@@ -1,18 +1,38 @@
<template> <template>
<v-snackbar <Notivue v-slot="item">
v-model="sb.showMsg" <NotivueSwipe :item="item">
location="top" <Notification
:color="snackbar.color" :item="item"
:timeout="snackbar.timeout"> :theme="theme"
{{ snackbar.message }} :dir="direction"
</v-snackbar> :icons="outlinedIcons"
:hideClose="true"
@click="item.clear"
/>
</NotivueSwipe>
</Notivue>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from 'vue' import { Notivue, Notification, NotivueSwipe, outlinedIcons, pastelTheme, darkTheme } from 'notivue'
import Message from '@/store/modules/message' import { computed } from 'vue'
import { useTheme } from 'vuetify'
import vuetify from '@/plugins/vuetify';
const sb = Message() const Theme = useTheme()
const snackbar = ref(sb.snackbar) const theme = computed(() =>{
return Theme.global.name.value == "light" ? pastelTheme : darkTheme
})
const direction = computed(() => {
return vuetify.locale.current.value == 'fa' ? 'rtl' : 'ltr'
})
</script> </script>
<style>
:root {
--nv-z: 10020;
}
</style>
+10 -5
View File
@@ -5,7 +5,7 @@
<v-row> <v-row>
<v-col>QrCode</v-col> <v-col>QrCode</v-col>
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-col cols="1"><v-icon icon="mdi-close-box" @click="$emit('close')" ></v-icon></v-col> <v-col cols="auto"><v-icon icon="mdi-close-box" @click="$emit('close')" /></v-col>
</v-row> </v-row>
</v-card-title> </v-card-title>
<v-divider></v-divider> <v-divider></v-divider>
@@ -31,14 +31,13 @@
import QrcodeVue from 'qrcode.vue' import QrcodeVue from 'qrcode.vue'
import Data from '@/store/modules/data' import Data from '@/store/modules/data'
import Clipboard from 'clipboard' import Clipboard from 'clipboard'
import Message from '@/store/modules/message'
import { i18n } from '@/locales' import { i18n } from '@/locales'
import { push } from 'notivue'
export default { export default {
props: ['index'], props: ['index'],
data() { data() {
return { return {
msg: Message(),
} }
}, },
methods: { methods: {
@@ -54,12 +53,18 @@ export default {
clipboard.on('success', () => { clipboard.on('success', () => {
clipboard.destroy() 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.on('error', () => {
clipboard.destroy() 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 // Perform click on hidden button to trigger copy
+1
View File
@@ -26,6 +26,7 @@ export default {
count: "Count", count: "Count",
error: { error: {
dplData: "Duplicate Data", dplData: "Duplicate Data",
core: "Sing-Box Error",
}, },
pages: { pages: {
login: "Login", login: "Login",
+1
View File
@@ -26,6 +26,7 @@ export default {
count: "تعداد", count: "تعداد",
error: { error: {
dplData: "داده تکراری", dplData: "داده تکراری",
core: "خطا در سینگ‌باکس",
}, },
pages: { pages: {
login: "ورود", login: "ورود",
+1
View File
@@ -26,6 +26,7 @@ export default {
count: "Đếm", count: "Đếm",
error: { error: {
dplData: "Dữ liệu trùng lặp", dplData: "Dữ liệu trùng lặp",
core: "Lỗi Sing-Box",
}, },
pages: { pages: {
login: "Đăng nhập", login: "Đăng nhập",
+1
View File
@@ -26,6 +26,7 @@ export default {
count: "计数", count: "计数",
error: { error: {
dplData: "重复数据", dplData: "重复数据",
core: "Sing-Box 错误",
}, },
pages: { pages: {
login: "登录", login: "登录",
+1
View File
@@ -27,6 +27,7 @@ export default {
count: "計數", count: "計數",
error: { error: {
dplData: "重複數據", dplData: "重複數據",
core: "Sing-Box 錯誤",
}, },
pages: { pages: {
login: "登錄", login: "登錄",
+17
View File
@@ -23,6 +23,22 @@ import { registerPlugins } from '@/plugins'
import { i18n } from '@/locales' import { i18n } from '@/locales'
import Vue3PersianDatetimePicker from 'vue3-persian-datetime-picker' 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 loading = ref(false)
const app = createApp(App) const app = createApp(App)
@@ -34,5 +50,6 @@ app
.use(router) .use(router)
.use(store) .use(store)
.use(i18n) .use(i18n)
.use(notivue)
.component('DatePicker', Vue3PersianDatetimePicker) .component('DatePicker', Vue3PersianDatetimePicker)
.mount('#app') .mount('#app')
+14 -5
View File
@@ -1,7 +1,7 @@
import api from './api' import api from './api'
import { i18n } from '@/locales' import { i18n } from '@/locales'
import router from '@/router' import router from '@/router'
import Message from "@/store/modules/message" import { push } from 'notivue'
export interface Msg { export interface Msg {
success: boolean success: boolean
@@ -10,18 +10,27 @@ export interface Msg {
} }
function _handleMsg(msg: any): void { function _handleMsg(msg: any): void {
const sb = Message()
if (!isMsg(msg)) { if (!isMsg(msg)) {
return return
} }
if(msg.msg){ if(msg.msg){
if (!msg.success && msg.msg == "Invalid login") { if (!msg.success && msg.msg == "Invalid login") {
sb.showMessage(i18n.global.t('invalidLogin'),'error', 5000) push.error({
title: i18n.global.t('invalidLogin'),
})
logout() logout()
return return
} }
const message = msg.success ? i18n.global.t('success') + ": " + i18n.global.t('actions.' + msg.msg) : i18n.global.t('failed') + ": " + msg.msg if (msg.success) {
sb.showMessage(message, msg.success ? 'success' : 'error', 5000) push.success({
message: i18n.global.t('success') + ": " + i18n.global.t('actions.' + msg.msg),
})
} else {
push.error({
title: i18n.global.t('failed'),
message: msg.msg
})
}
} }
} }
+7 -3
View File
@@ -1,7 +1,8 @@
import { FindDiff } from '@/plugins/utils' import { FindDiff } from '@/plugins/utils'
import HttpUtils from '@/plugins/httputil' import HttpUtils from '@/plugins/httputil'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import Message from './message' import { push } from 'notivue'
import { i18n } from '@/locales'
const Data = defineStore('Data', { const Data = defineStore('Data', {
state: () => ({ state: () => ({
@@ -26,8 +27,11 @@ const Data = defineStore('Data', {
if (msg.obj.tls) this.oldData.tlsConfigs = msg.obj.tls if (msg.obj.tls) this.oldData.tlsConfigs = msg.obj.tls
this.onlines = msg.obj.onlines this.onlines = msg.obj.onlines
if (msg.obj.lastLog) { if (msg.obj.lastLog) {
const sb = Message() push.error({
sb.showMessage('Core error: \n' + msg.obj.lastLog,'error', 5000) title: i18n.global.t('error.core'),
duration: 5000,
message: msg.obj.lastLog
})
} }
if (msg.obj.config) { if (msg.obj.config) {
-22
View File
@@ -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
+4 -3
View File
@@ -135,8 +135,8 @@ import { Config, V2rayApiStats } from '@/types/config'
import { InTypes, Inbound,InboundWithUser, ShadowTLS, VLESS } from '@/types/inbounds' import { InTypes, Inbound,InboundWithUser, ShadowTLS, VLESS } from '@/types/inbounds'
import { Link, LinkUtil } from '@/plugins/link' import { Link, LinkUtil } from '@/plugins/link'
import { HumanReadable } from '@/plugins/utils' import { HumanReadable } from '@/plugins/utils'
import Message from '@/store/modules/message'
import { i18n } from '@/locales' import { i18n } from '@/locales'
import { push } from 'notivue'
const clients = computed((): any[] => { const clients = computed((): any[] => {
return Data().clients return Data().clients
@@ -185,8 +185,9 @@ const saveModal = (data:any, stats:boolean) => {
// Check duplicate name // Check duplicate name
const oldName = modal.value.index != -1 ? clients.value[modal.value.index].name : null 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) { if (data.name != oldName && clients.value.findIndex(c => c.name == data.name) != -1) {
const sb = Message() push.error({
sb.showMessage(i18n.global.t('error.dplData') + ': ' + i18n.global.t('client.name') ,'error', 5000) message: i18n.global.t('error.dplData') + ": " + i18n.global.t('client.name')
})
return return
} }
if(modal.value.index == -1) { if(modal.value.index == -1) {
+4 -3
View File
@@ -109,8 +109,8 @@ import { computed, ref } from 'vue'
import { InTypes, Inbound, InboundWithUser, ShadowTLS, VLESS } from '@/types/inbounds' import { InTypes, Inbound, InboundWithUser, ShadowTLS, VLESS } from '@/types/inbounds'
import { Client } from '@/types/clients' import { Client } from '@/types/clients'
import { Link, LinkUtil } from '@/plugins/link' import { Link, LinkUtil } from '@/plugins/link'
import Message from '@/store/modules/message'
import { i18n } from '@/locales' import { i18n } from '@/locales'
import { push } from 'notivue'
const appConfig = computed((): Config => { const appConfig = computed((): Config => {
return <Config> Data().config return <Config> Data().config
@@ -166,8 +166,9 @@ const saveModal = (data:Inbound, stats: boolean, tls_id: number) => {
// Check duplicate tag // Check duplicate tag
const oldTag = modal.value.id != -1 ? inbounds.value[modal.value.id].tag : null const oldTag = modal.value.id != -1 ? inbounds.value[modal.value.id].tag : null
if (data.tag != oldTag && inTags.value.includes(data.tag)) { if (data.tag != oldTag && inTags.value.includes(data.tag)) {
const sb = Message() push.error({
sb.showMessage(i18n.global.t('error.dplData') + ': ' + i18n.global.t('objects.tag') ,'error', 5000) message: i18n.global.t('error.dplData') + ": " + i18n.global.t('objects.tag')
})
return return
} }
+4 -3
View File
@@ -96,8 +96,8 @@ import Stats from '@/layouts/modals/Stats.vue'
import { Config, V2rayApiStats } from '@/types/config'; import { Config, V2rayApiStats } from '@/types/config';
import { Outbound } from '@/types/outbounds'; import { Outbound } from '@/types/outbounds';
import { computed, ref } from 'vue' import { computed, ref } from 'vue'
import Message from '@/store/modules/message';
import { i18n } from '@/locales'; import { i18n } from '@/locales';
import { push } from 'notivue';
const appConfig = computed((): Config => { const appConfig = computed((): Config => {
return <Config> Data().config return <Config> Data().config
@@ -142,8 +142,9 @@ const saveModal = (data:Outbound, stats: boolean) => {
// Check duplicate tag // Check duplicate tag
const oldTag = modal.value.id != -1 ? outbounds.value[modal.value.id].tag : null const oldTag = modal.value.id != -1 ? outbounds.value[modal.value.id].tag : null
if (data.tag != oldTag && outboundTags.value.includes(data.tag)) { if (data.tag != oldTag && outboundTags.value.includes(data.tag)) {
const sb = Message() push.error({
sb.showMessage(i18n.global.t('error.dplData') + ': ' + i18n.global.t('objects.tag') ,'error', 5000) message: i18n.global.t('error.dplData') + ": " + i18n.global.t('objects.tag')
})
return return
} }
// New or Edit // New or Edit