mirror of
https://github.com/Kuingsmile/PicList.git
synced 2026-05-21 08:11:25 +08:00
✨ Feature(custom): rewrite setting page, WIP
This commit is contained in:
@@ -110,7 +110,7 @@ import { reactive, ref, toRefs, watch } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
import { getConfig } from '@/utils/dataSender'
|
||||
import { IPicGoPluginConfig, IStringKeyMap } from '#/types/types'
|
||||
import type { IPicGoPluginConfig, IStringKeyMap } from '#/types/types'
|
||||
|
||||
interface IProps {
|
||||
config: any[]
|
||||
|
||||
@@ -83,7 +83,7 @@ import { cloneDeep, union } from 'lodash-es'
|
||||
import { reactive, ref, watch } from 'vue'
|
||||
|
||||
import { getConfig } from '@/utils/dataSender'
|
||||
import { IPicGoPluginConfig, IStringKeyMap } from '#/types/types'
|
||||
import type { IPicGoPluginConfig, IStringKeyMap } from '#/types/types'
|
||||
|
||||
interface IProps {
|
||||
config: any[]
|
||||
|
||||
@@ -24,7 +24,7 @@ import { Loading } from '@element-plus/icons-vue'
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
|
||||
import { getFileIconPath } from '@/manage/utils/common'
|
||||
import { IRPCActionType } from '#/types/enum'
|
||||
import { IRPCActionType } from '@/utils/enum'
|
||||
|
||||
const preSignedUrl = ref('')
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ElIcon, ElImage } from 'element-plus'
|
||||
import { computed, defineComponent, onMounted, ref, watch } from 'vue'
|
||||
|
||||
import { getFileIconPath } from '@/manage/utils/common'
|
||||
import { IRPCActionType } from '#/types/enum'
|
||||
import { IRPCActionType } from '@/utils/enum'
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
|
||||
@@ -511,8 +511,8 @@ import type { IBuildInCompressOptions, IBuildInWaterMarkOptions } from 'piclist'
|
||||
import { computed, onBeforeMount, reactive, ref, toRaw } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import { configPaths } from '@/utils/configPaths'
|
||||
import { getConfig, saveConfig } from '@/utils/dataSender'
|
||||
import { configPaths } from '#/utils/configPaths'
|
||||
|
||||
const { t } = useI18n()
|
||||
const imageProcessDialogVisible = defineModel<boolean>()
|
||||
|
||||
@@ -25,7 +25,7 @@ import { computed, onMounted, ref, watch } from 'vue'
|
||||
|
||||
import { getFileIconPath } from '@/manage/utils/common'
|
||||
import { getAuthHeader } from '@/manage/utils/digestAuth'
|
||||
import { formatEndpoint } from '#/utils/common'
|
||||
import { formatEndpoint } from '@/utils/common'
|
||||
|
||||
const base64Url = ref('')
|
||||
const success = ref(false)
|
||||
|
||||
@@ -4,7 +4,7 @@ import { computed, defineComponent, onMounted, ref, watch } from 'vue'
|
||||
|
||||
import { getFileIconPath } from '@/manage/utils/common'
|
||||
import { getAuthHeader } from '@/manage/utils/digestAuth'
|
||||
import { formatEndpoint } from '#/utils/common'
|
||||
import { formatEndpoint } from '@/utils/common'
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
|
||||
@@ -32,8 +32,8 @@ import type { IpcRendererEvent } from 'electron'
|
||||
import { onBeforeMount, onBeforeUnmount, reactive, ref } from 'vue'
|
||||
|
||||
import $bus from '@/utils/bus'
|
||||
import { SHOW_INPUT_BOX, SHOW_INPUT_BOX_RESPONSE } from '#/events/constants'
|
||||
import { IShowInputBoxOption } from '#/types/types'
|
||||
import { SHOW_INPUT_BOX, SHOW_INPUT_BOX_RESPONSE } from '@/utils/constant'
|
||||
import type { IShowInputBoxOption } from '#/types/types'
|
||||
|
||||
const inputBoxValue = ref('')
|
||||
const showInputBoxVisible = ref(false)
|
||||
|
||||
@@ -218,14 +218,14 @@ import { pick } from 'lodash-es'
|
||||
import { BadgeInfoIcon, CheckIcon, ChevronDownIcon, CopyIcon, DatabaseIcon, FolderIcon, PieChartIcon, PlugIcon, Settings, UploadIcon } from 'lucide-vue-next'
|
||||
import QrcodeVue from 'qrcode.vue'
|
||||
import pkg from 'root/package.json'
|
||||
import { SHOW_MAIN_PAGE_QRCODE } from 'root/src/universal/events/constants'
|
||||
import { computed, nextTick, onBeforeMount, reactive, Ref, ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import * as config from '@/router/config'
|
||||
import { SHOW_MAIN_PAGE_QRCODE } from '@/utils/constant'
|
||||
import { getConfig } from '@/utils/dataSender'
|
||||
import { IRPCActionType } from '@/utils/enum'
|
||||
import { picBedGlobal, updatePicBedGlobal } from '@/utils/global'
|
||||
import { IRPCActionType } from '#/types/enum'
|
||||
|
||||
import ThemeSwitcher from './ui/ThemeSwitcher.vue'
|
||||
const version = ref(pkg.version)
|
||||
|
||||
@@ -11,10 +11,9 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { IToolboxItemCheckStatus } from '#/types/enum'
|
||||
|
||||
interface IProps {
|
||||
status: IToolboxItemCheckStatus
|
||||
status: string
|
||||
value: any
|
||||
handlerText: string
|
||||
handler: (value: any) => void | Promise<void>
|
||||
|
||||
@@ -19,10 +19,10 @@
|
||||
import { CircleCloseFilled, Loading, SuccessFilled } from '@element-plus/icons-vue'
|
||||
import { computed } from 'vue'
|
||||
|
||||
import { IToolboxItemCheckStatus } from '#/types/enum'
|
||||
import { IToolboxItemCheckStatus } from '@/utils/enum'
|
||||
|
||||
interface IProps {
|
||||
status: IToolboxItemCheckStatus
|
||||
status: string
|
||||
}
|
||||
|
||||
const props = defineProps<IProps>()
|
||||
|
||||
342
src/renderer/components/ui/ConfirmMessageBox.vue
Normal file
342
src/renderer/components/ui/ConfirmMessageBox.vue
Normal file
@@ -0,0 +1,342 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="isOpen"
|
||||
class="messagebox-overlay"
|
||||
@click="onCancel"
|
||||
>
|
||||
<div
|
||||
class="messagebox-container"
|
||||
@click.stop
|
||||
>
|
||||
<div class="messagebox-header">
|
||||
<h3 class="messagebox-title">
|
||||
{{ title }}
|
||||
</h3>
|
||||
<button
|
||||
v-if="showClose"
|
||||
class="messagebox-close"
|
||||
@click="onCancel"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
<div class="messagebox-content">
|
||||
<div
|
||||
v-if="type"
|
||||
class="messagebox-icon"
|
||||
>
|
||||
<component
|
||||
:is="iconComponent"
|
||||
:size="48"
|
||||
/>
|
||||
</div>
|
||||
<div class="messagebox-message">
|
||||
<p>{{ message }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="center"
|
||||
class="messagebox-actions center"
|
||||
>
|
||||
<button
|
||||
class="messagebox-btn cancel-btn"
|
||||
@click="onCancel"
|
||||
>
|
||||
{{ cancelButtonText }}
|
||||
</button>
|
||||
<button
|
||||
class="messagebox-btn confirm-btn"
|
||||
:class="confirmButtonClass"
|
||||
@click="onConfirm"
|
||||
>
|
||||
{{ confirmButtonText }}
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="messagebox-actions"
|
||||
>
|
||||
<button
|
||||
class="messagebox-btn confirm-btn"
|
||||
:class="confirmButtonClass"
|
||||
@click="onConfirm"
|
||||
>
|
||||
{{ confirmButtonText }}
|
||||
</button>
|
||||
<button
|
||||
class="messagebox-btn cancel-btn"
|
||||
@click="onCancel"
|
||||
>
|
||||
{{ cancelButtonText }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { AlertTriangle, CheckCircle, Info, XCircle } from 'lucide-vue-next'
|
||||
import { computed } from 'vue'
|
||||
|
||||
interface Props {
|
||||
isOpen: boolean
|
||||
title?: string
|
||||
message: string
|
||||
type?: 'info' | 'success' | 'warning' | 'error'
|
||||
confirmButtonText?: string
|
||||
cancelButtonText?: string
|
||||
showClose?: boolean
|
||||
center?: boolean
|
||||
}
|
||||
|
||||
interface Emits {
|
||||
(e: 'confirm'): void
|
||||
(e: 'cancel'): void
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
title: 'Confirm',
|
||||
confirmButtonText: 'Confirm',
|
||||
cancelButtonText: 'Cancel',
|
||||
showClose: true,
|
||||
center: false,
|
||||
type: undefined
|
||||
})
|
||||
|
||||
const emit = defineEmits<Emits>()
|
||||
|
||||
const iconComponent = computed(() => {
|
||||
switch (props.type) {
|
||||
case 'warning':
|
||||
return AlertTriangle
|
||||
case 'info':
|
||||
return Info
|
||||
case 'success':
|
||||
return CheckCircle
|
||||
case 'error':
|
||||
return XCircle
|
||||
default:
|
||||
return Info
|
||||
}
|
||||
})
|
||||
|
||||
const confirmButtonClass = computed(() => {
|
||||
switch (props.type) {
|
||||
case 'warning':
|
||||
case 'error':
|
||||
return 'danger'
|
||||
case 'success':
|
||||
return 'success'
|
||||
default:
|
||||
return 'primary'
|
||||
}
|
||||
})
|
||||
|
||||
const onConfirm = () => {
|
||||
emit('confirm')
|
||||
}
|
||||
|
||||
const onCancel = () => {
|
||||
emit('cancel')
|
||||
}
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'ConfirmMessageBox'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.messagebox-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
.messagebox-container {
|
||||
background: white;
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
max-width: 32rem;
|
||||
width: 90%;
|
||||
max-height: 80vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
:root.dark .messagebox-container,
|
||||
:root.auto.dark .messagebox-container {
|
||||
background: rgb(31 41 55);
|
||||
border: 1px solid rgb(55 65 81);
|
||||
}
|
||||
|
||||
.messagebox-header {
|
||||
padding: 1.5rem 1.5rem 0 1.5rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.messagebox-title {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
color: rgb(17 24 39);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
:root.dark .messagebox-title,
|
||||
:root.auto.dark .messagebox-title {
|
||||
color: rgb(243 244 246);
|
||||
}
|
||||
|
||||
.messagebox-close {
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 1.5rem;
|
||||
color: rgb(107 114 128);
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
|
||||
.messagebox-close:hover {
|
||||
background: rgb(243 244 246);
|
||||
color: rgb(17 24 39);
|
||||
}
|
||||
|
||||
:root.dark .messagebox-close,
|
||||
:root.auto.dark .messagebox-close {
|
||||
color: rgb(156 163 175);
|
||||
}
|
||||
|
||||
:root.dark .messagebox-close:hover,
|
||||
:root.auto.dark .messagebox-close:hover {
|
||||
background: rgb(55 65 81);
|
||||
color: rgb(243 244 246);
|
||||
}
|
||||
|
||||
.messagebox-content {
|
||||
padding: 1rem 1.5rem;
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.messagebox-icon {
|
||||
flex-shrink: 0;
|
||||
color: rgb(107 114 128);
|
||||
}
|
||||
|
||||
.messagebox-icon svg[data-lucide="alert-triangle"] {
|
||||
color: rgb(245 158 11);
|
||||
}
|
||||
|
||||
.messagebox-icon svg[data-lucide="info"] {
|
||||
color: rgb(59 130 246);
|
||||
}
|
||||
|
||||
.messagebox-icon svg[data-lucide="check-circle"] {
|
||||
color: rgb(34 197 94);
|
||||
}
|
||||
|
||||
.messagebox-icon svg[data-lucide="x-circle"] {
|
||||
color: rgb(239 68 68);
|
||||
}
|
||||
|
||||
.messagebox-message {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.messagebox-message p {
|
||||
color: rgb(107 114 128);
|
||||
line-height: 1.6;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
:root.dark .messagebox-message p,
|
||||
:root.auto.dark .messagebox-message p {
|
||||
color: rgb(156 163 175);
|
||||
}
|
||||
|
||||
.messagebox-actions {
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
padding: 0 1.5rem 1.5rem 1.5rem;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.messagebox-actions.center {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.messagebox-btn {
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 0.375rem;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
min-width: 4rem;
|
||||
}
|
||||
|
||||
.cancel-btn {
|
||||
background: rgb(243 244 246);
|
||||
color: rgb(75 85 99);
|
||||
border: 1px solid rgb(209 213 219);
|
||||
}
|
||||
|
||||
.cancel-btn:hover {
|
||||
background: rgb(229 231 235);
|
||||
}
|
||||
|
||||
:root.dark .cancel-btn,
|
||||
:root.auto.dark .cancel-btn {
|
||||
background: rgb(55 65 81);
|
||||
color: rgb(209 213 219);
|
||||
border-color: rgb(75 85 99);
|
||||
}
|
||||
|
||||
:root.dark .cancel-btn:hover,
|
||||
:root.auto.dark .cancel-btn:hover {
|
||||
background: rgb(75 85 99);
|
||||
}
|
||||
|
||||
.confirm-btn.primary {
|
||||
background: rgb(59 130 246);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.confirm-btn.primary:hover {
|
||||
background: rgb(37 99 235);
|
||||
}
|
||||
|
||||
.confirm-btn.danger {
|
||||
background: rgb(239 68 68);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.confirm-btn.danger:hover {
|
||||
background: rgb(220 38 38);
|
||||
}
|
||||
|
||||
.confirm-btn.success {
|
||||
background: rgb(34 197 94);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.confirm-btn.success:hover {
|
||||
background: rgb(22 163 74);
|
||||
}
|
||||
</style>
|
||||
260
src/renderer/components/ui/MessageToast.vue
Normal file
260
src/renderer/components/ui/MessageToast.vue
Normal file
@@ -0,0 +1,260 @@
|
||||
<template>
|
||||
<Teleport to="body">
|
||||
<div class="message-container">
|
||||
<TransitionGroup
|
||||
name="message"
|
||||
tag="div"
|
||||
>
|
||||
<div
|
||||
v-for="message in messages"
|
||||
:key="message.id"
|
||||
class="message-toast"
|
||||
:class="getMessageClass(message.type)"
|
||||
>
|
||||
<div class="message-icon">
|
||||
<component
|
||||
:is="getIconComponent(message.type)"
|
||||
:size="20"
|
||||
/>
|
||||
</div>
|
||||
<div class="message-content">
|
||||
{{ message.message }}
|
||||
</div>
|
||||
<button
|
||||
v-if="message.showClose"
|
||||
class="message-close"
|
||||
@click="removeMessage(message.id)"
|
||||
>
|
||||
<X :size="16" />
|
||||
</button>
|
||||
</div>
|
||||
</TransitionGroup>
|
||||
</div>
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { AlertTriangle, CheckCircle, Info, X, XCircle } from 'lucide-vue-next'
|
||||
import { reactive } from 'vue'
|
||||
|
||||
export interface MessageOptions {
|
||||
message: string
|
||||
type?: 'success' | 'warning' | 'info' | 'error'
|
||||
duration?: number
|
||||
showClose?: boolean
|
||||
}
|
||||
|
||||
interface MessageItem extends MessageOptions {
|
||||
id: string
|
||||
timer?: ReturnType<typeof setTimeout>
|
||||
}
|
||||
|
||||
const messages = reactive<MessageItem[]>([])
|
||||
|
||||
const getIconComponent = (type: MessageOptions['type']) => {
|
||||
switch (type) {
|
||||
case 'success':
|
||||
return CheckCircle
|
||||
case 'warning':
|
||||
return AlertTriangle
|
||||
case 'error':
|
||||
return XCircle
|
||||
default:
|
||||
return Info
|
||||
}
|
||||
}
|
||||
|
||||
const getMessageClass = (type: MessageOptions['type']) => {
|
||||
return `message-${type || 'info'}`
|
||||
}
|
||||
|
||||
const removeMessage = (id: string) => {
|
||||
const index = messages.findIndex(msg => msg.id === id)
|
||||
if (index > -1) {
|
||||
const message = messages[index]
|
||||
if (message.timer) {
|
||||
clearTimeout(message.timer)
|
||||
}
|
||||
messages.splice(index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
const addMessage = (options: MessageOptions) => {
|
||||
const id = `message-${Date.now()}-${Math.random()}`
|
||||
const duration = options.duration ?? 3000
|
||||
const showClose = options.showClose ?? true
|
||||
|
||||
const message: MessageItem = {
|
||||
id,
|
||||
...options,
|
||||
showClose
|
||||
}
|
||||
|
||||
if (duration > 0) {
|
||||
message.timer = setTimeout(() => {
|
||||
removeMessage(id)
|
||||
}, duration)
|
||||
}
|
||||
|
||||
messages.push(message)
|
||||
return id
|
||||
}
|
||||
|
||||
// Expose methods for external use
|
||||
const success = (message: string, options?: Partial<MessageOptions>) => {
|
||||
return addMessage({ message, type: 'success', ...options })
|
||||
}
|
||||
|
||||
const error = (message: string, options?: Partial<MessageOptions>) => {
|
||||
return addMessage({ message, type: 'error', ...options })
|
||||
}
|
||||
|
||||
const warning = (message: string, options?: Partial<MessageOptions>) => {
|
||||
return addMessage({ message, type: 'warning', ...options })
|
||||
}
|
||||
|
||||
const info = (message: string, options?: Partial<MessageOptions>) => {
|
||||
return addMessage({ message, type: 'info', ...options })
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
success,
|
||||
error,
|
||||
warning,
|
||||
info,
|
||||
addMessage,
|
||||
removeMessage
|
||||
})
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'MessageToast'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.message-container {
|
||||
position: fixed;
|
||||
top: 34px;
|
||||
right: 20px;
|
||||
z-index: 3000;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.message-toast {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 0.75rem 1rem;
|
||||
margin-bottom: 0.5rem;
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
max-width: 24rem;
|
||||
pointer-events: all;
|
||||
background: white;
|
||||
border: 1px solid rgb(229 231 235);
|
||||
}
|
||||
|
||||
:root.dark .message-toast,
|
||||
:root.auto.dark .message-toast {
|
||||
background: rgb(31 41 55);
|
||||
border-color: rgb(55 65 81);
|
||||
}
|
||||
|
||||
.message-info {
|
||||
border-left: 4px solid rgb(59 130 246);
|
||||
}
|
||||
|
||||
.message-info .message-icon {
|
||||
color: rgb(59 130 246);
|
||||
}
|
||||
|
||||
.message-success {
|
||||
border-left: 4px solid rgb(34 197 94);
|
||||
}
|
||||
|
||||
.message-success .message-icon {
|
||||
color: rgb(34 197 94);
|
||||
}
|
||||
|
||||
.message-warning {
|
||||
border-left: 4px solid rgb(245 158 11);
|
||||
}
|
||||
|
||||
.message-warning .message-icon {
|
||||
color: rgb(245 158 11);
|
||||
}
|
||||
|
||||
.message-error {
|
||||
border-left: 4px solid rgb(239 68 68);
|
||||
}
|
||||
|
||||
.message-error .message-icon {
|
||||
color: rgb(239 68 68);
|
||||
}
|
||||
|
||||
.message-icon {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.message-content {
|
||||
flex: 1;
|
||||
color: rgb(75 85 99);
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.25rem;
|
||||
}
|
||||
|
||||
:root.dark .message-content,
|
||||
:root.auto.dark .message-content {
|
||||
color: rgb(209 213 219);
|
||||
}
|
||||
|
||||
.message-close {
|
||||
background: none;
|
||||
border: none;
|
||||
color: rgb(107 114 128);
|
||||
cursor: pointer;
|
||||
padding: 0.25rem;
|
||||
border-radius: 0.25rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.message-close:hover {
|
||||
background: rgb(243 244 246);
|
||||
color: rgb(75 85 99);
|
||||
}
|
||||
|
||||
:root.dark .message-close,
|
||||
:root.auto.dark .message-close {
|
||||
color: rgb(156 163 175);
|
||||
}
|
||||
|
||||
:root.dark .message-close:hover,
|
||||
:root.auto.dark .message-close:hover {
|
||||
background: rgb(55 65 81);
|
||||
color: rgb(209 213 219);
|
||||
}
|
||||
|
||||
/* Transition animations */
|
||||
.message-enter-active,
|
||||
.message-leave-active {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.message-enter-from {
|
||||
opacity: 0;
|
||||
transform: translateX(100%);
|
||||
}
|
||||
|
||||
.message-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(100%);
|
||||
}
|
||||
|
||||
.message-move {
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
</style>
|
||||
@@ -3,7 +3,7 @@ import { Monitor, Moon, Sun } from 'lucide-vue-next'
|
||||
import { computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import { useAppStore } from '@/hooks/appStore'
|
||||
import { useAppStore } from '@/hooks/useAppStore'
|
||||
|
||||
const { t } = useI18n()
|
||||
const appStore = useAppStore()
|
||||
|
||||
@@ -78,7 +78,7 @@ import type { IpcRendererEvent } from 'electron'
|
||||
import { MinusIcon, PinIcon, ShrinkIcon, XIcon } from 'lucide-vue-next'
|
||||
import { onBeforeMount, onBeforeUnmount, ref } from 'vue'
|
||||
|
||||
import { IRPCActionType } from '#/types/enum'
|
||||
import { IRPCActionType } from '@/utils/enum'
|
||||
|
||||
const isShowprogress = ref(false)
|
||||
const progress = ref(0)
|
||||
|
||||
101
src/renderer/components/ui/UIServiceProvider.vue
Normal file
101
src/renderer/components/ui/UIServiceProvider.vue
Normal file
@@ -0,0 +1,101 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- MessageToast component -->
|
||||
<MessageToast ref="messageRef" />
|
||||
|
||||
<!-- ConfirmMessageBox component -->
|
||||
<ConfirmMessageBox
|
||||
:is-open="confirmVisible"
|
||||
:title="confirmOptions.title"
|
||||
:message="confirmOptions.message"
|
||||
:type="confirmOptions.type"
|
||||
:confirm-button-text="confirmOptions.confirmButtonText"
|
||||
:cancel-button-text="confirmOptions.cancelButtonText"
|
||||
:show-close="confirmOptions.showClose"
|
||||
:center="confirmOptions.center"
|
||||
@confirm="handleConfirm"
|
||||
@cancel="handleCancel"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, reactive, ref } from 'vue'
|
||||
|
||||
import useConfirm, { type ConfirmOptions } from '@/hooks/useConfirm'
|
||||
import useMessage from '@/hooks/useMessage'
|
||||
|
||||
import ConfirmMessageBox from './ConfirmMessageBox.vue'
|
||||
import MessageToast from './MessageToast.vue'
|
||||
|
||||
const messageRef = ref<InstanceType<typeof MessageToast> | null>(null)
|
||||
const confirmVisible = ref(false)
|
||||
const confirmOptions = reactive<ConfirmOptions>({
|
||||
message: '',
|
||||
title: 'Confirm',
|
||||
type: 'info',
|
||||
confirmButtonText: 'Confirm',
|
||||
cancelButtonText: 'Cancel',
|
||||
showClose: true,
|
||||
center: false
|
||||
})
|
||||
|
||||
let confirmResolve: ((value: boolean) => void) | null = null
|
||||
|
||||
const handleConfirm = () => {
|
||||
confirmVisible.value = false
|
||||
if (confirmResolve) {
|
||||
confirmResolve(true)
|
||||
confirmResolve = null
|
||||
}
|
||||
}
|
||||
|
||||
const handleCancel = () => {
|
||||
confirmVisible.value = false
|
||||
if (confirmResolve) {
|
||||
confirmResolve(false)
|
||||
confirmResolve = null
|
||||
}
|
||||
}
|
||||
|
||||
const showConfirm = (options: ConfirmOptions): Promise<boolean> => {
|
||||
return new Promise((resolve) => {
|
||||
Object.assign(confirmOptions, {
|
||||
title: 'Confirm',
|
||||
type: 'info',
|
||||
confirmButtonText: 'Confirm',
|
||||
cancelButtonText: 'Cancel',
|
||||
showClose: true,
|
||||
center: false,
|
||||
...options
|
||||
})
|
||||
confirmResolve = resolve
|
||||
confirmVisible.value = true
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// Initialize message service
|
||||
const { setMessageService } = useMessage()
|
||||
if (messageRef.value) {
|
||||
setMessageService({
|
||||
success: messageRef.value.success,
|
||||
error: messageRef.value.error,
|
||||
warning: messageRef.value.warning,
|
||||
info: messageRef.value.info
|
||||
})
|
||||
}
|
||||
|
||||
// Initialize confirm service
|
||||
const { setConfirmService } = useConfirm()
|
||||
setConfirmService({
|
||||
confirm: showConfirm
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'UIServiceProvider'
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user