🌻 update(custom): 更新侧边栏功能显示

This commit is contained in:
nongyehong 2024-03-06 08:03:27 +08:00
parent 196d2d12a8
commit acc01945d4
19 changed files with 297 additions and 129 deletions

View File

@ -7,7 +7,7 @@
<title>Tauri + Vue + TS</title>
<!--引入iconpark图标库-->
<script defer src="https://lf1-cdn-tos.bytegoofy.com/obj/iconpark/svg_30895_61.f6c25d2ccb13bf96747417c789d6c0f4.js"></script>
<script defer src="https://lf1-cdn-tos.bytegoofy.com/obj/iconpark/svg_30895_63.de195ae6484b5e9104a9599e1be84393.js"></script>
</head>
<body>

View File

@ -1,7 +1,7 @@
{
"name": "hula-im-tauri",
"private": true,
"version": "v1.0.0-alpha",
"version": "v1.2.8-alpha",
"packageManager": "pnpm@8.14.1",
"engines": {
"node": ">=18.12.0",
@ -47,6 +47,7 @@
},
"devDependencies": {
"@babel/eslint-parser": "^7.23.3",
"@rollup/plugin-terser": "^0.4.4",
"@tauri-apps/cli": "^1.5.7",
"@types/lodash-es": "^4.17.12",
"@types/node": "^20.10.4",

View File

@ -43,6 +43,9 @@ devDependencies:
'@babel/eslint-parser':
specifier: ^7.23.3
version: 7.23.9(@babel/core@7.24.0)(eslint@8.56.0)
'@rollup/plugin-terser':
specifier: ^0.4.4
version: 0.4.4
'@tauri-apps/cli':
specifier: ^1.5.7
version: 1.5.9
@ -1079,6 +1082,20 @@ packages:
resolution: {integrity: sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==}
dev: true
/@rollup/plugin-terser@0.4.4:
resolution: {integrity: sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==}
engines: {node: '>=14.0.0'}
peerDependencies:
rollup: ^2.0.0||^3.0.0||^4.0.0
peerDependenciesMeta:
rollup:
optional: true
dependencies:
serialize-javascript: 6.0.2
smob: 1.4.1
terser: 5.28.1
dev: true
/@rollup/pluginutils@5.1.0:
resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==}
engines: {node: '>=14.0.0'}
@ -5210,6 +5227,10 @@ packages:
is-fullwidth-code-point: 5.0.0
dev: true
/smob@1.4.1:
resolution: {integrity: sha512-9LK+E7Hv5R9u4g4C3p+jjLstaLe11MDsL21UpYaCNmapvMkYhqCV4A/f/3gyH8QjMyh6l68q9xC85vihY9ahMQ==}
dev: true
/source-map-js@1.0.2:
resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
engines: {node: '>=0.10.0'}

View File

@ -7,7 +7,7 @@
},
"package": {
"productName": "HuLa-IM-Tauri",
"version": "0.0.0"
"version": "v1.2.8-alpha"
},
"tauri": {
"allowlist": {

View File

@ -27,14 +27,14 @@ onMounted(() => {
}
document.documentElement.dataset.theme = THEME.value
window.addEventListener('dragstart', preventDrag)
// /* */
// window.addEventListener('keydown', (e) => {
// if (e.ctrlKey || e.metaKey || e.altKey) {
// e.preventDefault()
// }
// })
// /* */
// window.addEventListener('contextmenu', (e) => e.preventDefault(), false)
/* 禁用浏览器默认的快捷键 */
window.addEventListener('keydown', (e) => {
if (e.ctrlKey || e.metaKey || e.altKey) {
e.preventDefault()
}
})
/* 禁止右键菜单 */
window.addEventListener('contextmenu', (e) => e.preventDefault(), false)
})
onUnmounted(() => {

View File

@ -10,8 +10,18 @@ export const maximizeWindow = async () => {
await appWindow.maximize()
}
/** 关闭 */
export const closeWindow = async () => {
/**
*
* @param label
* @example
* 使appWindow.emit事件
* 事件名称: windowsClose
*/
export const closeWindow = async (label: string) => {
if (label !== void 0) {
const win = WebviewWindow.getByLabel(label)
win?.emit('windowsClose', label)
}
await appWindow.close()
}

View File

@ -82,6 +82,9 @@ const themeOverrides: GlobalThemeOverrides = {
tabTextColorActiveSegment: '#059669',
tabTextColorHoverSegment: '#059669',
tabPaddingMediumSegment: '4px'
},
Popover: {
padding: '5px'
}
}

View File

@ -6,21 +6,13 @@
<!-- 输入框顶部选项栏 -->
<nav class="flex-between-center p-[10px_22px_5px] select-none">
<nav class="input-options flex-y-center">
<n-popover
trigger="hover"
:show-arrow="false"
placement="bottom"
style="padding: 5px; border: 1px solid rgba(90, 90, 90, 0.3)">
<n-popover trigger="hover" :show-arrow="false" placement="bottom">
<template #trigger>
<svg class="mr-18px"><use href="#smiling-face"></use></svg>
</template>
<span>表情</span>
</n-popover>
<n-popover
trigger="hover"
:show-arrow="false"
placement="bottom"
style="padding: 5px; border: 1px solid rgba(90, 90, 90, 0.3)">
<n-popover trigger="hover" :show-arrow="false" placement="bottom">
<template #trigger>
<div class="flex-center gap-2px mr-12px">
<svg><use href="#screenshot"></use></svg>
@ -29,11 +21,7 @@
</template>
<span>截图</span>
</n-popover>
<n-popover
trigger="hover"
:show-arrow="false"
placement="bottom"
style="padding: 5px; border: 1px solid rgba(90, 90, 90, 0.3)">
<n-popover trigger="hover" :show-arrow="false" placement="bottom">
<template #trigger>
<div class="flex-center gap-2px mr-12px">
<svg><use href="#file2"></use></svg>
@ -42,41 +30,25 @@
</template>
<span>文件</span>
</n-popover>
<n-popover
trigger="hover"
:show-arrow="false"
placement="bottom"
style="padding: 5px; border: 1px solid rgba(90, 90, 90, 0.3)">
<n-popover trigger="hover" :show-arrow="false" placement="bottom">
<template #trigger>
<svg class="mr-18px"><use href="#photo"></use></svg>
</template>
<span>图片</span>
</n-popover>
<n-popover
trigger="hover"
:show-arrow="false"
placement="bottom"
style="padding: 5px; border: 1px solid rgba(90, 90, 90, 0.3)">
<n-popover trigger="hover" :show-arrow="false" placement="bottom">
<template #trigger>
<svg class="mr-18px"><use href="#shake"></use></svg>
</template>
<span>窗口抖动</span>
</n-popover>
<n-popover
trigger="hover"
:show-arrow="false"
placement="bottom"
style="padding: 5px; border: 1px solid rgba(90, 90, 90, 0.3)">
<n-popover trigger="hover" :show-arrow="false" placement="bottom">
<template #trigger>
<svg class="mr-18px"><use href="#red-packet"></use></svg>
</template>
<span>红包</span>
</n-popover>
<n-popover
trigger="hover"
:show-arrow="false"
placement="bottom"
style="padding: 5px; border: 1px solid rgba(90, 90, 90, 0.3)">
<n-popover trigger="hover" :show-arrow="false" placement="bottom">
<template #trigger>
<svg class="mr-18px"><use href="#voice"></use></svg>
</template>
@ -84,11 +56,7 @@
</n-popover>
</nav>
<n-popover
trigger="hover"
:show-arrow="false"
placement="bottom"
style="padding: 5px; border: 1px solid rgba(90, 90, 90, 0.3)">
<n-popover trigger="hover" :show-arrow="false" placement="bottom">
<template #trigger>
<svg class="w-22px h-22px cursor-pointer outline-none"><use href="#history"></use></svg>
</template>

View File

@ -7,11 +7,7 @@
<!-- 顶部右边选项栏 -->
<nav class="options flex-y-center gap-20px color-[--icon-color]">
<div class="options-box">
<n-popover
trigger="hover"
:show-arrow="false"
placement="bottom"
style="padding: 5px; border: 1px solid rgba(90, 90, 90, 0.3)">
<n-popover trigger="hover" :show-arrow="false" placement="bottom">
<template #trigger>
<svg @click="handleClick"><use href="#phone-telephone"></use></svg>
</template>
@ -20,11 +16,7 @@
</div>
<div class="options-box">
<n-popover
trigger="hover"
:show-arrow="false"
placement="bottom"
style="padding: 5px; border: 1px solid rgba(90, 90, 90, 0.3)">
<n-popover trigger="hover" :show-arrow="false" placement="bottom">
<template #trigger>
<svg><use href="#video-one"></use></svg>
</template>
@ -33,11 +25,7 @@
</div>
<div class="options-box">
<n-popover
trigger="hover"
:show-arrow="false"
placement="bottom"
style="padding: 5px; border: 1px solid rgba(90, 90, 90, 0.3)">
<n-popover trigger="hover" :show-arrow="false" placement="bottom">
<template #trigger>
<svg><use href="#screen-sharing"></use></svg>
</template>
@ -46,11 +34,7 @@
</div>
<div class="options-box">
<n-popover
trigger="hover"
:show-arrow="false"
placement="bottom"
style="padding: 5px; border: 1px solid rgba(90, 90, 90, 0.3)">
<n-popover trigger="hover" :show-arrow="false" placement="bottom">
<template #trigger>
<svg><use href="#remote-control"></use></svg>
</template>
@ -59,11 +43,7 @@
</div>
<div class="options-box">
<n-popover
trigger="hover"
:show-arrow="false"
placement="bottom"
style="padding: 5px; border: 1px solid rgba(90, 90, 90, 0.3)">
<n-popover trigger="hover" :show-arrow="false" placement="bottom">
<template #trigger>
<svg><use href="#launch"></use></svg>
</template>

View File

@ -1,5 +1,5 @@
<template>
<component :is="componentMap[message.type]" :body="message.body" :data-message-id="message.id" />
<component :is="componentMap" :body="message.body" :data-message-id="message.id" />
</template>
<script setup lang="ts">
import { MsgEnum } from '@/enums'

View File

@ -1,6 +1,23 @@
<template>
<!-- user-select: none让元素不可以选中 -->
<div data-tauri-drag-region class="flex justify-end select-none">
<!-- 固定在最顶层 -->
<div v-if="topWinLabel !== void 0" @click="handleAlwaysOnTop" class="hover-box">
<n-popover trigger="hover">
<template #trigger>
<svg
v-if="alwaysOnTopStatus"
class="w-14px h-14px color-[--action-bar-icon-color] outline-none cursor-pointer">
<use href="#onTop"></use>
</svg>
<svg v-else class="w-16px h-16px color-[--action-bar-icon-color] outline-none cursor-pointer">
<use href="#notOnTop"></use>
</svg>
</template>
<span v-if="alwaysOnTopStatus">取消置顶</span>
<span v-else>置顶</span>
</n-popover>
</div>
<!-- 收缩页面 -->
<div v-if="shrink" @click="shrinkWindow" class="hover-box">
<svg class="w-16px h-16px color-[--action-bar-icon-color] cursor-pointer"><use href="#left-bar"></use></svg>
@ -21,7 +38,7 @@
</svg>
</div>
<!-- 关闭窗口 -->
<div v-if="closeW" @click="closeWindow" class="action-close">
<div v-if="closeW" @click="closeWindow(currentLabel as string)" class="action-close">
<svg class="w-14px h-14px color-[--action-bar-icon-color] cursor-pointer">
<use href="#close"></use>
</svg>
@ -34,6 +51,7 @@ import { closeWindow, maximizeWindow, minimizeWindow, unmaximize } from '@/commo
import { appWindow } from '@tauri-apps/api/window'
import Mitt from '@/utils/Bus'
import { useWindow } from '@/hooks/useWindow.ts'
import { alwaysOnTop } from '@/stores/alwaysOnTop.ts'
/**
* 新版defineProps可以直接结构 { minW, maxW, closeW } 如果需要使用默认值withDefaults的时候使用新版解构方式会报错
@ -45,6 +63,8 @@ const props = withDefaults(
maxW?: boolean
closeW?: boolean
shrink?: boolean
topWinLabel?: string
currentLabel?: string
shrinkStatus?: boolean
}>(),
{
@ -55,9 +75,22 @@ const props = withDefaults(
shrinkStatus: true
}
)
const { minW, maxW, closeW, shrinkStatus } = toRefs(props)
const windowMaximized = ref(false)
const { minW, maxW, closeW, topWinLabel, shrinkStatus } = toRefs(props)
const alwaysOnTopStore = alwaysOnTop()
const { resizeWindow } = useWindow()
//
const windowMaximized = ref(false)
//
const alwaysOnTopStatus = computed(() => {
if (topWinLabel.value === void 0) return false
return alwaysOnTopStore.getWindowTop(topWinLabel.value)
})
watchEffect(() => {
if (alwaysOnTopStatus.value) {
appWindow.setAlwaysOnTop(alwaysOnTopStatus.value as boolean)
}
})
// todo
// // unlisten
@ -98,6 +131,15 @@ const shrinkWindow = async () => {
await resizeWindow('home', 960, 700)
}
}
/* 设置窗口置顶 */
const handleAlwaysOnTop = async () => {
if (topWinLabel.value !== void 0) {
const isTop = !alwaysOnTopStatus.value
alwaysOnTopStore.setWindowTop(topWinLabel.value, isTop)
await appWindow.setAlwaysOnTop(isTop)
}
}
</script>
<style scoped lang="scss">
@ -105,6 +147,6 @@ const shrinkWindow = async () => {
@apply w-28px h24px flex-center hover:bg-[--action-bar-icon-hover];
}
.action-close {
@apply w-28px h24px flex-center cursor-pointer hover:bg-#c22b1c svg:hover:color-[#fff] rounded-tr-6px;
@apply w-28px h24px flex-center cursor-pointer hover:bg-#c22b1c svg:hover:color-[#fff];
}
</style>

View File

@ -42,10 +42,17 @@ export const useWindow = () => {
fileDropEnabled: isDrag
})
// 首先检查是否已经存在同名窗口
// TODO 这里如果主页刷新页面这样传递过来的label就没有了从而导致isExistsWinds为空的问题 (nyh -> 2024-03-06 06:33:38)
const isExistsWinds = WebviewWindow.getByLabel(label)
// TODO 页面刷新后很多状态会丢失,虽然上线打包后可以禁用刷新但难免会有些人会触发刷新,需要解决这个刷新后状态丢失问题 (nyh -> 2024-03-06 06:32:03)
if (isExistsWinds) {
// 如果窗口已存在,则给它焦点,使其置顶
// 如果窗口已存在,首先检查是否最小化了
const minimized = await webview.isMinimized()
if (minimized) {
// 如果已最小化,恢复窗口
await webview.unminimize()
}
// 如果窗口已存在,则给它焦点,使其在最前面显示
await webview.setFocus()
} else {
await webview.once('tauri://created', async () => {

View File

@ -9,11 +9,14 @@
v-for="(item, index) in itemsTop"
:key="index"
@click="pageJumps(item.url)"
class="top-action"
:class="{ active: activeItem === item.url }">
:class="[
{ active: activeItem === item.url && item.url !== 'dynamic' },
openWindowsList.has(item.url) ? 'p-[6px_8px] color-#059669' : 'top-action'
]">
<n-badge :value="item.badge" :max="99">
<svg class="w-22px h-22px">
<use :href="`#${activeItem === item.url && item.iconAction ? item.iconAction : item.icon}`"></use>
<use
:href="`#${activeItem === item.url || openWindowsList.has(item.url) ? item.iconAction : item.icon}`"></use>
</svg>
</n-badge>
</div>
@ -25,9 +28,9 @@
v-for="(item, index) in itemsBottom"
:key="index"
@click="openContent(item.title, item.label)"
class="bottom-action">
:class="openWindowsList.has(item.url.substring(1)) ? 'p-[6px_8px] color-#059669' : 'bottom-action'">
<svg class="w-22px h-22px">
<use :href="`#${item.icon}`"></use>
<use :href="`#${openWindowsList.has(item.url.substring(1)) ? item.iconAction : item.icon}`"></use>
</svg>
</div>
@ -55,6 +58,7 @@ import { delay } from 'lodash-es'
import { useWindow } from '@/hooks/useWindow.ts'
import router from '@/router'
import Mitt from '@/utils/Bus.ts'
import { listenMsg } from '@/common/CrossTabMsg.ts'
type TopActive = {
url: string
@ -156,6 +160,8 @@ const menuList = ref<MenuList>([
/*当前选中的元素 默认选中itemsTop的第一项*/
const activeItem = ref<string>(itemsTop.value[0].url)
const settingShow = ref(false)
/* 已打开窗口的列表 */
const openWindowsList = ref(new Set())
const { createWebviewWindow } = useWindow()
watchEffect(() => {
@ -166,6 +172,13 @@ watchEffect(() => {
}
})
})
listenMsg((msgInfo: any) => {
if (msgInfo.content.payload !== void 0) {
openWindowsList.value.delete(msgInfo.content.payload)
} else if (!openWindowsList.value.has(msgInfo.content)) {
openWindowsList.value.add(msgInfo.content)
}
})
})
/**
@ -173,13 +186,13 @@ watchEffect(() => {
* @param url 跳转的路由
* */
const pageJumps = (url: string) => {
activeItem.value = url
//
if (url === 'dynamic') {
delay(async () => {
await createWebviewWindow('动态', 'dynamic', 840, 800)
}, 300)
} else {
activeItem.value = url
router.push(`/${url}`)
}
}

View File

@ -19,7 +19,7 @@ const generateRandomString = (length: number, type: number) => {
}
export const MockList = ref<MockItem[]>(
Array.from({ length: 50 }, (_, i) => {
Array.from({ length: 20 }, (_, i) => {
const type = Math.round(Math.random()) + 1
return {
key: i,
@ -43,6 +43,7 @@ export const dynamicList = Array.from({ length: 10 }, (_, i) => {
id: i,
avatar: `${avatars}?${i}`,
user: `泰勒斯威夫特 ${i}`,
img: imgList
img: imgList,
isAuth: i % 2 === 0
}
})

22
src/stores/alwaysOnTop.ts Normal file
View File

@ -0,0 +1,22 @@
import { defineStore } from 'pinia'
interface AlwaysOnTopData {
isAlwaysOnTop: boolean
}
interface AlwaysOnTop {
[key: string]: AlwaysOnTopData | boolean
}
export const alwaysOnTop = defineStore('alwaysOnTop', {
state: (): AlwaysOnTop => ({}),
actions: {
setWindowTop(key: string, data: AlwaysOnTopData | boolean) {
this.$state[key] = data
},
getWindowTop(key: string) {
return this.$state[key]
}
},
persist: true
})

View File

@ -2,10 +2,10 @@
<!-- TODO 项目初次启动然后初次打开窗口时候这个页面的样式没有渲染出来 (nyh -> 2024-03-04 05:30:15) -->
<!-- TODO 我需要点击最左边侧边栏时候的选中样式如果是淡出弹出窗口就把图标点亮但是不用设置背景颜色然后如果关闭了对应窗口就把图标恢复原来的样式 (nyh -> 2024-03-04 05:32:03) -->
<main class="wh-full bg-[--right-bg-color]">
<ActionBar :shrink="false" :max-w="false" />
<article class="flex flex-col items-center text-color-[--text-color] wh-full bg-[--right-bg-color]">
<ActionBar :shrink="false" :max-w="false" :top-win-label="currentWindowLabel" :current-label="currentWindowLabel" />
<article class="flex flex-col items-center text-[--text-color] wh-full bg-[--right-bg-color]">
<n-scrollbar
style="max-height: 100vh"
style="max-height: calc(100vh - 20px)"
class="w-650px bg-[--center-bg-color] h-full p-[10px_0] box-border rounded-4px">
<n-flex justify="center">
<!-- 动态内容框 -->
@ -14,16 +14,18 @@
v-for="item in dynamicList"
:key="item.id"
class="w-450px h-fit rounded-8px bg-[--right-bg-color] p-10px box-border">
<n-flex>
<n-flex align="center">
<!-- 用户的头像和用户名以及个签 -->
<img class="w-45px h-45px bg-#ccc rounded-50% select-none" :src="item.avatar" alt="" />
<n-space vertical style="flex: 1">
<n-flex justify="space-between" align="center">
<label class="text-14px flex items-center gap-5px">
<span>泰勒斯威夫特</span>
<n-popover trigger="hover">
<span :class="item.isAuth ? 'text-#059669' : ''">{{ item.user }}</span>
<n-popover trigger="hover" v-if="item.isAuth">
<template #trigger>
<svg class="w-20px h-20px color-#059669 select-none outline-none"><use href="#auth"></use></svg>
<svg class="w-20px h-20px color-#059669 select-none outline-none cursor-pointer">
<use href="#auth"></use>
</svg>
</template>
<span>著名歌手</span>
</n-popover>
@ -62,5 +64,27 @@
</main>
</template>
<script setup lang="ts">
import { dynamicList } from '@/mock/index.ts'
import { dynamicList } from '@/mock'
import { appWindow, WebviewWindow } from '@tauri-apps/api/window'
import { sendMsg } from '@/common/CrossTabMsg.ts'
//
const currentWindowLabel = computed(() => {
return appWindow.label
})
const win = WebviewWindow.getByLabel(currentWindowLabel.value)
// TODO 使win.emit (nyh -> 2024-03-05 07:15:42)
watchEffect(() => {
win?.listen('windowsClose', (e) => {
sendMsg('windowsShow', e)
})
})
onMounted(async () => {
const isShow = await win?.isVisible()
if (isShow) {
sendMsg('windowsShow', currentWindowLabel.value)
}
})
</script>

View File

@ -1,10 +1,32 @@
<template>
<div class="wh-full bg-[--right-bg-color]">
<ActionBar :shrink="false" />
<ActionBar :shrink="false" :current-label="currentWindowLabel" />
<p>邮箱</p>
</div>
</template>
<script setup lang="ts"></script>
<script setup lang="ts">
import { appWindow, WebviewWindow } from '@tauri-apps/api/window'
import { sendMsg } from '@/common/CrossTabMsg.ts'
//
const currentWindowLabel = computed(() => {
return appWindow.label
})
const win = WebviewWindow.getByLabel(currentWindowLabel.value)
// TODO 使win.emit (nyh -> 2024-03-05 07:15:42)
watchEffect(() => {
win?.listen('windowsClose', (e) => {
sendMsg('windowsShow', e)
})
})
onMounted(async () => {
const isShow = await win?.isVisible()
if (isShow) {
sendMsg('windowsShow', currentWindowLabel.value)
}
})
</script>
<style scoped></style>

View File

@ -1,38 +1,40 @@
<template>
<!-- 消息列表 -->
<!-- 可拖拽排序组件 -->
<VueDraggable v-if="MockList.length > 0" ref="el" :animation="150" v-model="MockList">
<VueDraggable v-if="MockList.length > 0" ref="el" target=".sort-target" :animation="150" v-model="MockList">
<!-- 右键菜单组件 -->
<ContextMenu
@select="handleSelect($event.click(item.key))"
@click="handleMsgClick(item)"
:menu="menuList"
:special-menu="specialMenuList"
:class="{ active: activeItem === item.key }"
class="msg-box w-full h-75px mb-5px"
v-for="item in MockList"
:key="item.key">
<!-- 消息框使用v-slide自定义指令来自动抉择右键菜单位置 -->
<div v-slide class="flex items-center h-full pl-6px pr-8px gap-10px">
<img class="w-44px h-44px rounded-50% bg-#fff" style="border: 1px solid #f1f1f1" :src="item.avatar" alt="" />
<TransitionGroup type="transition" tag="div" name="fade" class="sort-target">
<ContextMenu
@select="handleSelect($event.click(item.key))"
@click="handleMsgClick(item)"
:menu="menuList"
:special-menu="specialMenuList"
:class="{ active: activeItem === item.key }"
class="msg-box w-full h-75px mb-5px"
v-for="item in MockList"
:key="item.key">
<!-- 消息框使用v-slide自定义指令来自动抉择右键菜单位置 -->
<div v-slide class="flex items-center h-full pl-6px pr-8px gap-10px">
<img class="w-44px h-44px rounded-50% bg-#fff" style="border: 1px solid #f1f1f1" :src="item.avatar" alt="" />
<div class="h-38px flex flex-1 flex-col justify-between">
<div class="flex-between-center">
<span class="text-14px">{{ item.accountName }}</span>
<span class="text text-10px">昨天</span>
</div>
<div class="h-38px flex flex-1 flex-col justify-between">
<div class="flex-between-center">
<span class="text-14px">{{ item.accountName }}</span>
<span class="text text-10px">昨天</span>
</div>
<div class="flex-between-center">
<p class="text w-135px text-12px" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis">
说的很经典哈萨克的哈萨克看到贺卡上
</p>
<div class="flex-between-center">
<p class="text w-135px text-12px" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis">
说的很经典哈萨克的哈萨克看到贺卡上
</p>
<!-- 消息提示 -->
<n-badge :value="msgTotal" :max="99" />
<!-- 消息提示 -->
<n-badge :value="msgTotal" :max="99" />
</div>
</div>
</div>
</div>
</ContextMenu>
</ContextMenu>
</TransitionGroup>
</VueDraggable>
<!-- 暂无消息 -->
@ -126,6 +128,9 @@ onMounted(() => {
<style scoped lang="scss">
.msg-box {
transition:
background-color 0.3s ease,
border-radius 0.3s ease;
color: var(--text-color);
.text {
color: #808080;
@ -150,6 +155,24 @@ onMounted(() => {
}
}
/*! TransitionGroup过渡样式 */
.fade-move,
.fade-enter-active,
.fade-leave-active {
transition: all 0.5s cubic-bezier(0.55, 0, 0.1, 1);
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
transform: scaleY(0.01) translate(30px, 0);
}
.fade-leave-active {
position: absolute;
}
/*! end */
:deep(.n-badge .n-badge-sup) {
font-weight: bold;
font-size: 10px;

View File

@ -6,6 +6,7 @@ import { NaiveUiResolver } from 'unplugin-vue-components/resolvers'
import { getRootPath, getSrcPath } from './build/config/getPath'
import vueJsx from '@vitejs/plugin-vue-jsx'
import unocss from '@unocss/vite'
import terser from '@rollup/plugin-terser'
// https://vitejs.dev/config/
export default defineConfig(({ mode }: ConfigEnv) => {
@ -50,8 +51,38 @@ export default defineConfig(({ mode }: ConfigEnv) => {
dirs: ['src/components/**'], // 设置需要扫描的目录
resolvers: [NaiveUiResolver()],
dts: 'src/typings/components.d.ts'
}),
/* 压缩代码 */
terser({
format: {
comments: false // 移除所有注释
},
compress: {
drop_console: true, // 移除 console.log
drop_debugger: true // 移除 debugger
}
})
],
build: {
cssCodeSplit: true, // 启用 CSS 代码拆分
minify: 'terser', // 指定使用哪种混淆器
// chunk 大小警告的限制(kb)
chunkSizeWarningLimit: 1200,
// 分包配置
rollupOptions: {
output: {
chunkFileNames: 'static/js/[name]-[hash].js', // 引入文件名的名称
entryFileNames: 'static/js/[name]-[hash].js', // 包的入口文件名称
assetFileNames: 'static/[ext]/[name]-[hash].[ext]', // 资源文件像 字体,图片等
// 最小化拆分包
manualChunks(id) {
if (id.includes('node_modules')) {
return id.toString().split('node_modules/')[1].split('/')[0].toString()
}
}
}
}
},
// Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build`
//