| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { GroupLite, User } from '../types' |
| | | |
| | | import { reactive, ref } from 'vue' |
| | | |
| | | import { acceptHMRUpdate, defineStore } from 'pinia' |
| | | |
| | | import { ImFriendAddSource } from '../../utils/constants' |
| | | |
| | | /** |
| | | * IM å
¨å± UI store |
| | | * |
| | | * æ¶çº³æ åï¼è§¦åç¹ N 个ãæè½½ç¹æ³ä¿æ 1 ä¸ªçæµ®å±ç¶æã |
| | | * ä»»æä½ç½®é½å¯è½ openï¼ä½ DOM ä¸åªæ³çä¸ä»½å®ä¾ â èµ° store æ´¾åï¼ |
| | | * ç± `index.vue` æä¸ä¸ªè®¢é
ç»ä»¶ç»ä¸æ¸²æã |
| | | */ |
| | | export const useImUiStore = defineStore('imUiStore', () => { |
| | | // ==================== ç¨æ·åç UserInfoCard ==================== |
| | | // ç¨æ·åçæ¬æµ®å¡ |
| | | |
| | | const userInfoCard = reactive({ |
| | | show: false, |
| | | user: null as null | User, |
| | | position: { x: 0, y: 0 }, |
| | | // addSource / addSourceExtra è·é触åç¹å¸¦å
¥ãå 好åãæ¥æºï¼ç¾¤æåå
¥å£ = GROUP + 群åï¼å
¶ä½é»è®¤æç´¢ï¼ |
| | | addSource: ImFriendAddSource.SEARCH as number, |
| | | addSourceExtra: '' as string |
| | | }) |
| | | |
| | | /** æå¼ç¨æ·åç */ |
| | | function openUserInfoCard( |
| | | user: User, |
| | | position: { x: number; y: number }, |
| | | addSource: number = ImFriendAddSource.SEARCH, |
| | | addSourceExtra: string = '' |
| | | ) { |
| | | const viewportWidth = document.documentElement.clientWidth |
| | | const viewportHeight = document.documentElement.clientHeight |
| | | userInfoCard.user = user |
| | | userInfoCard.position.x = Math.min(position.x, viewportWidth - 350) |
| | | userInfoCard.position.y = Math.min(position.y, viewportHeight - 220) |
| | | userInfoCard.addSource = addSource |
| | | userInfoCard.addSourceExtra = addSourceExtra |
| | | userInfoCard.show = true |
| | | } |
| | | |
| | | /** é¼ æ ç¹å»ä½ç½® + 20px 横ååç§»æå¼åçï¼é¿å
åçç´æ¥è¦ç触åå
ç´ ï¼å¯¹é½å¤´å / åçæ¶æ¯çç¹å»äº¤äºçç»ä¸è§æ */ |
| | | function openUserInfoCardAtEvent( |
| | | user: User, |
| | | e: MouseEvent, |
| | | addSource: number = ImFriendAddSource.SEARCH, |
| | | addSourceExtra: string = '' |
| | | ) { |
| | | openUserInfoCard(user, { x: e.clientX + 20, y: e.clientY }, addSource, addSourceExtra) |
| | | } |
| | | |
| | | /** å
³éç¨æ·åç */ |
| | | function closeUserInfoCard() { |
| | | userInfoCard.show = false |
| | | } |
| | | |
| | | // ==================== 群åç GroupInfoCard ==================== |
| | | |
| | | const groupInfoCard = reactive({ |
| | | show: false, |
| | | group: null as GroupLite | null, |
| | | position: { x: 0, y: 0 } |
| | | }) |
| | | |
| | | /** é¼ æ ç¹å»ä½ç½® + 20px 横ååç§»æå¼ç¾¤åçï¼å¯¹é½ UserInfoCard çç»ä¸è§æ */ |
| | | function openGroupInfoCardAtEvent(group: GroupLite, e: MouseEvent) { |
| | | const viewportWidth = document.documentElement.clientWidth |
| | | const viewportHeight = document.documentElement.clientHeight |
| | | groupInfoCard.group = group |
| | | groupInfoCard.position.x = Math.min(e.clientX + 20, viewportWidth - 350) |
| | | groupInfoCard.position.y = Math.min(e.clientY, viewportHeight - 220) |
| | | groupInfoCard.show = true |
| | | } |
| | | |
| | | /** å
³é群åç */ |
| | | function closeGroupInfoCard() { |
| | | groupInfoCard.show = false |
| | | } |
| | | |
| | | // ==================== å³é®èå ContextMenu ==================== |
| | | // å³é®èåè½ç¶æ¯ä¸ä¸ªç»ä»¶æå¨ä¸»å£³ä¸ï¼ä½å
¶è§¦åæ¶æºåæ£å¨åå表 |
| | | interface ContextMenuItem { |
| | | key: string |
| | | name: string |
| | | disabled?: boolean |
| | | divided?: boolean // æ¯å¦å¨è¯¥é¡¹ä¸æ¹æ¾ç¤ºåå²çº¿ï¼ç¨äºæ"å é¤"çå±é©æä½ä¸ä¸é¢ç常è§é¡¹éå¼ï¼ |
| | | danger?: boolean // æ¯å¦èµ°å±é©æä½æ ·å¼ï¼çº¢è²æåï¼ |
| | | icon?: string // å¯é iconify 徿 åï¼å¦ ant-design:delete-outlinedï¼ï¼ä¸ä¼ å䏿¸²æåç½®å¾æ |
| | | } |
| | | |
| | | const contextMenu = reactive({ |
| | | show: false, |
| | | position: { x: 0, y: 0 }, |
| | | items: [] as ContextMenuItem[], |
| | | /** éä¸åè°ï¼æ¯æ¬¡ open æ¶ç±è°ç¨æ¹ä¼ å
¥ */ |
| | | onSelect: null as ((item: ContextMenuItem) => void) | null |
| | | }) |
| | | |
| | | /** æå¼å³é®èå */ |
| | | function openContextMenu( |
| | | position: { x: number; y: number }, |
| | | items: ContextMenuItem[], |
| | | onSelect: (item: ContextMenuItem) => void |
| | | ) { |
| | | contextMenu.position = position |
| | | contextMenu.items = items |
| | | contextMenu.onSelect = onSelect |
| | | contextMenu.show = true |
| | | } |
| | | |
| | | /** å
³éå³é®èå */ |
| | | function closeContextMenu() { |
| | | contextMenu.show = false |
| | | contextMenu.onSelect = null |
| | | } |
| | | |
| | | // ==================== æ¶æ¯ Tab 跳转ä¸ä¸æªè¯» ==================== |
| | | // å¨ ImHomeConversation 页é¢å次ç¹å»å·¥å
·æ ãæ¶æ¯ãæ¶è§¦åï¼ |
| | | // éè¿éå¢ nonce 让 conversation/index.vue ç watch æç¥åæ§è¡æ»å¨ + é«äº® |
| | | |
| | | const nextUnreadJumpNonce = ref(0) |
| | | |
| | | /** è¯·æ±æ»å¨å°ä¸ä¸ä¸ªæªè¯»ä¼è¯ï¼å«å
ææ°ï¼ */ |
| | | function requestNextUnreadJump() { |
| | | nextUnreadJumpNonce.value++ |
| | | } |
| | | |
| | | return { |
| | | userInfoCard, |
| | | openUserInfoCard, |
| | | openUserInfoCardAtEvent, |
| | | closeUserInfoCard, |
| | | |
| | | groupInfoCard, |
| | | openGroupInfoCardAtEvent, |
| | | closeGroupInfoCard, |
| | | |
| | | contextMenu, |
| | | openContextMenu, |
| | | closeContextMenu, |
| | | |
| | | nextUnreadJumpNonce, |
| | | requestNextUnreadJump |
| | | } |
| | | }) |
| | | |
| | | // dev: 让 Pinia ç actions / state æ¹å¨æ¯æ HMRï¼é¿å
æ¯æ¬¡æ¹ store é½å¾ç¡¬å· |
| | | // å¦å Vite ææ°æ¨¡åæ¨ä¸æ¥åï¼è store å®ä¾ç action éå
仿忧彿°ä½ |
| | | if (import.meta.hot) { |
| | | import.meta.hot.accept(acceptHMRUpdate(useImUiStore, import.meta.hot)) |
| | | } |