koishi-plugin-chat-patch 3.0.2 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (237) hide show
  1. package/client/vue/index.vue +60 -634
  2. package/client/web/dist/assets/AppIcon-DIku6-h0.png +0 -0
  3. package/client/web/dist/assets/AppIconDark-BYymN71t.png +0 -0
  4. package/client/web/dist/assets/CapacitorAppIcon-CSZwNhvi.png +0 -0
  5. package/client/web/dist/assets/CapacitorAppIconDark-BMvMOzsg.png +0 -0
  6. package/client/web/dist/assets/Chat-CTdyeaX2.css +1 -0
  7. package/client/web/dist/assets/Chat-DkZvD7d8.js +28 -0
  8. package/client/web/dist/assets/MealHungryPan-Beos3lRI.js +1 -0
  9. package/client/web/dist/assets/MsgBody-aZ4_aija.js +1 -0
  10. package/client/web/dist/assets/MsgBody.vue_vue_type_script_setup_true_lang-CPZjRLp6.js +67 -0
  11. package/client/web/dist/assets/NapcatAppIcon-C7VOAkW9.png +0 -0
  12. package/client/web/dist/assets/Vue-lEhHouxB.png +0 -0
  13. package/client/web/dist/assets/append_darwin-CqBNU62J.css +1 -0
  14. package/client/web/dist/assets/append_full_vibrancy-j0D2LM9m.css +1 -0
  15. package/client/web/dist/assets/append_linux-uhxeBqeC.css +1 -0
  16. package/client/web/dist/assets/append_linux_vibrancy-COiZq8MS.css +1 -0
  17. package/client/web/dist/assets/append_napcat-DV8CAyAd.css +1 -0
  18. package/client/web/dist/assets/append_new-407Lo5_V.css +1 -0
  19. package/client/web/dist/assets/append_vibrancy-6FHctkOY.css +1 -0
  20. package/client/web/dist/assets/append_win32-srmD-78y.css +1 -0
  21. package/client/web/dist/assets/cakes-CxTVKdnK.svg +189 -0
  22. package/client/web/dist/assets/core-DhEqZVGG.js +1 -0
  23. package/client/web/dist/assets/event-Cadp6m6J.js +1 -0
  24. package/client/web/dist/assets/index-CPTXiemn.js +4045 -0
  25. package/client/web/dist/assets/index-Cg_esKB0.js +1 -0
  26. package/client/web/dist/assets/index-Cln012sP.css +1 -0
  27. package/client/web/dist/assets//346/226/271/346/255/243/345/226/265/345/221/234/344/275/223-CJKIKBn3.ttf +0 -0
  28. package/client/web/dist/assets//346/234/237/345/276/205-C90_OY60.png +0 -0
  29. package/client/web/dist/bcui/css/color-dark.css +35 -0
  30. package/client/web/dist/bcui/css/color-light.css +35 -0
  31. package/client/web/dist/bcui/css/style.css +468 -0
  32. package/client/web/dist/bcui/js/main.js +193 -0
  33. package/client/web/dist/css/append-dark.css +13 -0
  34. package/client/web/dist/css/append-light.css +13 -0
  35. package/client/web/dist/css/append-napcat-dark.css +14 -0
  36. package/client/web/dist/css/append-napcat-light.css +14 -0
  37. package/client/web/dist/favicon.ico +0 -0
  38. package/client/web/dist/img/icons/icon-for-fuck-apple.png +0 -0
  39. package/client/web/dist/img/icons/icon-maskable.png +0 -0
  40. package/client/web/dist/img/icons/icon.png +0 -0
  41. package/client/web/dist/img/icons/icon.svg +10 -0
  42. package/client/web/dist/index.html +22 -0
  43. package/client/web/dist/robots.txt +2 -0
  44. package/client/web/dist/sw.js +58 -0
  45. package/client/web/env.d.ts +56 -0
  46. package/client/web/index.html +21 -0
  47. package/client/web/package-lock.json +3419 -0
  48. package/client/web/package.json +62 -0
  49. package/client/web/public/bcui/css/color-dark.css +35 -0
  50. package/client/web/public/bcui/css/color-light.css +35 -0
  51. package/client/web/public/bcui/css/style.css +468 -0
  52. package/client/web/public/bcui/js/main.js +193 -0
  53. package/client/web/public/css/append-dark.css +13 -0
  54. package/client/web/public/css/append-light.css +13 -0
  55. package/client/web/public/css/append-napcat-dark.css +14 -0
  56. package/client/web/public/css/append-napcat-light.css +14 -0
  57. package/client/web/public/favicon.ico +0 -0
  58. package/client/web/public/img/icons/icon-for-fuck-apple.png +0 -0
  59. package/client/web/public/img/icons/icon-maskable.png +0 -0
  60. package/client/web/public/img/icons/icon.png +0 -0
  61. package/client/web/public/img/icons/icon.svg +10 -0
  62. package/client/web/public/robots.txt +2 -0
  63. package/client/web/public/sw.js +58 -0
  64. package/client/web/scripts/copy-bcui.mjs +17 -0
  65. package/client/web/src/App.vue +1127 -0
  66. package/client/web/src/assets/css/append/append_darwin.css +68 -0
  67. package/client/web/src/assets/css/append/append_full_vibrancy.css +290 -0
  68. package/client/web/src/assets/css/append/append_linux.css +125 -0
  69. package/client/web/src/assets/css/append/append_linux_vibrancy.css +22 -0
  70. package/client/web/src/assets/css/append/append_napcat.css +35 -0
  71. package/client/web/src/assets/css/append/append_new.css +843 -0
  72. package/client/web/src/assets/css/append/append_vibrancy.css +113 -0
  73. package/client/web/src/assets/css/append/append_win32.css +109 -0
  74. package/client/web/src/assets/css/append/mobile/append_mobile_horizontal.css +349 -0
  75. package/client/web/src/assets/css/append/mobile/append_mobile_vertical.css +96 -0
  76. package/client/web/src/assets/css/chat.css +2104 -0
  77. package/client/web/src/assets/css/msg.css +941 -0
  78. package/client/web/src/assets/css/options.css +811 -0
  79. package/client/web/src/assets/css/sys_notice.css +62 -0
  80. package/client/web/src/assets/css/view.css +2105 -0
  81. package/client/web/src/assets/font//346/226/271/346/255/243/345/226/265/345/221/234/344/275/223.ttf +0 -0
  82. package/client/web/src/assets/img/Vue.png +0 -0
  83. package/client/web/src/assets/img/cakes.svg +189 -0
  84. package/client/web/src/assets/img/icons/AppIcon.png +0 -0
  85. package/client/web/src/assets/img/icons/AppIconDark.png +0 -0
  86. package/client/web/src/assets/img/icons/CapacitorAppIcon.png +0 -0
  87. package/client/web/src/assets/img/icons/CapacitorAppIconDark.png +0 -0
  88. package/client/web/src/assets/img/icons/NapcatAppIcon.png +0 -0
  89. package/client/web/src/assets/img/icons/NapcatAppIconDark.png +0 -0
  90. package/client/web/src/assets/img/icons/exit.png +0 -0
  91. package/client/web/src/assets/img/icons/pen.png +0 -0
  92. package/client/web/src/assets/img/stars.svg +89 -0
  93. package/client/web/src/assets/img//346/234/237/345/276/205.png +0 -0
  94. package/client/web/src/assets/l10n/_About I10n.md +35 -0
  95. package/client/web/src/assets/l10n/_l10nconfig.json +7 -0
  96. package/client/web/src/assets/l10n/zh-CN.po +1941 -0
  97. package/client/web/src/assets/logo.png +0 -0
  98. package/client/web/src/assets/pathMap/LLOneBot.yaml +2 -0
  99. package/client/web/src/assets/pathMap/Lagrange.OneBot.yaml +180 -0
  100. package/client/web/src/assets/pathMap/NapCat.Onebot.yaml +224 -0
  101. package/client/web/src/assets/pathMap/SnowLuma.yaml +80 -0
  102. package/client/web/src/assets/qed.txt +1 -0
  103. package/client/web/src/components/AboutPan.vue +197 -0
  104. package/client/web/src/components/BulletinBody.vue +129 -0
  105. package/client/web/src/components/DepPan.vue +310 -0
  106. package/client/web/src/components/EmojiFace.vue +32 -0
  107. package/client/web/src/components/FacePan.vue +461 -0
  108. package/client/web/src/components/FileBody.vue +129 -0
  109. package/client/web/src/components/FileManager.vue +532 -0
  110. package/client/web/src/components/FriendBody.vue +54 -0
  111. package/client/web/src/components/GlobalSessionSearchBar.vue +301 -0
  112. package/client/web/src/components/History.vue +49 -0
  113. package/client/web/src/components/LazyLottie.vue +82 -0
  114. package/client/web/src/components/MergePan.vue +127 -0
  115. package/client/web/src/components/MsgBody.vue +1478 -0
  116. package/client/web/src/components/MusicPlayer.vue +549 -0
  117. package/client/web/src/components/NoticeBody.vue +168 -0
  118. package/client/web/src/components/QzonePermissionPan.vue +150 -0
  119. package/client/web/src/components/RawMsgRenderPreviewPan.vue +190 -0
  120. package/client/web/src/components/ThemeColorPickerPan.vue +420 -0
  121. package/client/web/src/components/TinySessionBody.vue +51 -0
  122. package/client/web/src/components/UmamiInfoPan.vue +1549 -0
  123. package/client/web/src/components/UpdatePan.vue +263 -0
  124. package/client/web/src/components/ViewerCom.vue +1360 -0
  125. package/client/web/src/components/VoiceMsg.vue +626 -0
  126. package/client/web/src/components/WelPan.vue +894 -0
  127. package/client/web/src/components/msg-body/.gitkeep +0 -0
  128. package/client/web/src/components/msg-component/JsonSegComp.vue +138 -0
  129. package/client/web/src/components/msg-component/XmlSegComp.vue +132 -0
  130. package/client/web/src/components/msg-component/jsonComp/AutoReply.vue +97 -0
  131. package/client/web/src/components/msg-component/jsonComp/Contact.lua.vue +129 -0
  132. package/client/web/src/components/msg-component/jsonComp/Feed.lua.vue +94 -0
  133. package/client/web/src/components/msg-component/jsonComp/Forum.vue +84 -0
  134. package/client/web/src/components/msg-component/jsonComp/Mannounce.vue +111 -0
  135. package/client/web/src/components/msg-component/jsonComp/Map.vue +52 -0
  136. package/client/web/src/components/msg-component/jsonComp/Miniapp.lua.vue +53 -0
  137. package/client/web/src/components/msg-component/jsonComp/Miniapp.vue +69 -0
  138. package/client/web/src/components/msg-component/jsonComp/Music.lua.vue +135 -0
  139. package/client/web/src/components/msg-component/jsonComp/Tuwen.lua.vue +56 -0
  140. package/client/web/src/components/notice-component/.gitkeep +0 -0
  141. package/client/web/src/components/notice-component/MealHungryPan.vue +119 -0
  142. package/client/web/src/components/tooltip/CustomFaceTooltip.vue +22 -0
  143. package/client/web/src/components/tooltip/Tooltip.vue +50 -0
  144. package/client/web/src/components/tooltip/Tooltips.vue +14 -0
  145. package/client/web/src/components/tooltip/UserInfoTooltip.vue +69 -0
  146. package/client/web/src/function/base.ts +238 -0
  147. package/client/web/src/function/connect.ts +2042 -0
  148. package/client/web/src/function/debug.ts +10 -0
  149. package/client/web/src/function/elements/information.ts +141 -0
  150. package/client/web/src/function/elements/system.ts +101 -0
  151. package/client/web/src/function/elements/vueComp.ts +62 -0
  152. package/client/web/src/function/favicon.ts +76 -0
  153. package/client/web/src/function/input.ts +69 -0
  154. package/client/web/src/function/model/emoji.ts +127 -0
  155. package/client/web/src/function/model/img.ts +150 -0
  156. package/client/web/src/function/model/msg-body.ts +51 -0
  157. package/client/web/src/function/msg.ts +2674 -0
  158. package/client/web/src/function/notify.ts +225 -0
  159. package/client/web/src/function/option.ts +749 -0
  160. package/client/web/src/function/satori-model.ts +818 -0
  161. package/client/web/src/function/satori.ts +325 -0
  162. package/client/web/src/function/sender.ts +178 -0
  163. package/client/web/src/function/tooltip.ts +49 -0
  164. package/client/web/src/function/utils/appUtil.ts +2288 -0
  165. package/client/web/src/function/utils/avatarUtil.ts +31 -0
  166. package/client/web/src/function/utils/backgroundUtil.ts +110 -0
  167. package/client/web/src/function/utils/linkViewUtil.ts +101 -0
  168. package/client/web/src/function/utils/localHistoryUtil.ts +517 -0
  169. package/client/web/src/function/utils/msgUtil.ts +1242 -0
  170. package/client/web/src/function/utils/pinyin.ts +141 -0
  171. package/client/web/src/function/utils/recordUtil.ts +187 -0
  172. package/client/web/src/function/utils/sessionUtil.ts +114 -0
  173. package/client/web/src/function/utils/systemUtil.ts +664 -0
  174. package/client/web/src/main.ts +91 -0
  175. package/client/web/src/pages/Chat.vue +3453 -0
  176. package/client/web/src/pages/Friends.vue +636 -0
  177. package/client/web/src/pages/Info.vue +717 -0
  178. package/client/web/src/pages/Messages.vue +875 -0
  179. package/client/web/src/pages/Options.vue +82 -0
  180. package/client/web/src/pages/Qzone.vue +1178 -0
  181. package/client/web/src/pages/chat-view/ChatDanmaku.vue +759 -0
  182. package/client/web/src/pages/chat-view/ChatGlagame.vue +642 -0
  183. package/client/web/src/pages/chat-view/ChatTerminal.vue +1044 -0
  184. package/client/web/src/pages/chat-view/SystemNotice.vue +171 -0
  185. package/client/web/src/pages/options/OptAccount.vue +107 -0
  186. package/client/web/src/pages/options/OptAddon.vue +185 -0
  187. package/client/web/src/pages/options/OptDev.vue +704 -0
  188. package/client/web/src/pages/options/OptFunction.vue +403 -0
  189. package/client/web/src/pages/options/OptInfo.vue +165 -0
  190. package/client/web/src/pages/options/OptView.vue +846 -0
  191. package/client/web/src/runtime/backend.ts +310 -0
  192. package/client/web/src/state/auth.ts +14 -0
  193. package/client/web/src/state/chat.ts +36 -0
  194. package/client/web/src/state/connection.ts +20 -0
  195. package/client/web/src/state/contact.ts +37 -0
  196. package/client/web/src/state/qzone.ts +18 -0
  197. package/client/web/src/state/sessionHistory.ts +25 -0
  198. package/client/web/src/state/settings.ts +18 -0
  199. package/client/web/src/state/sticker.ts +10 -0
  200. package/client/web/src/state/ui.ts +56 -0
  201. package/client/web/tsconfig.json +27 -0
  202. package/client/web/tsconfig.tsbuildinfo +1 -0
  203. package/client/web/vite.config.ts +33 -0
  204. package/dist/index.js +1 -12
  205. package/dist/style.css +1 -1
  206. package/lib/index.js +2070 -2077
  207. package/package.json +15 -2
  208. package/readme.md +0 -22
  209. package/src/bootstrap.ts +71 -0
  210. package/src/cache.ts +319 -0
  211. package/src/config.ts +23 -35
  212. package/src/database.ts +650 -0
  213. package/src/index.ts +27 -59
  214. package/src/media.ts +302 -0
  215. package/src/recorder.ts +175 -0
  216. package/src/self-message.ts +456 -0
  217. package/src/server.d.ts +26 -0
  218. package/src/types.ts +108 -48
  219. package/src/web.ts +712 -0
  220. package/client/vue/chat-logic.ts +0 -683
  221. package/client/vue/composables/useChatActions.ts +0 -61
  222. package/client/vue/composables/useChatData.ts +0 -185
  223. package/client/vue/composables/useImageCache.ts +0 -281
  224. package/client/vue/composables/useVideoCache.ts +0 -125
  225. package/client/vue/types.ts +0 -72
  226. package/lib/api-handlers.d.ts +0 -25
  227. package/lib/config.d.ts +0 -14
  228. package/lib/file-manager.d.ts +0 -124
  229. package/lib/index.d.ts +0 -17
  230. package/lib/logger.d.ts +0 -9
  231. package/lib/message-handler.d.ts +0 -35
  232. package/lib/types.d.ts +0 -57
  233. package/lib/utils.d.ts +0 -18
  234. package/src/api-handlers.ts +0 -646
  235. package/src/file-manager.ts +0 -1436
  236. package/src/message-handler.ts +0 -507
  237. package/src/utils.ts +0 -189
@@ -0,0 +1,875 @@
1
+ <!--
2
+ * @FileDescription: 消息列表页面
3
+ * @Author: Stapxs
4
+ * @Date:
5
+ * 2022/08/14
6
+ * 2022/12/14
7
+ * @Version:
8
+ * 1.0 - 初始版本
9
+ * 1.5 - 重构为 ts 版本,代码格式优化
10
+ -->
11
+
12
+ <template>
13
+ <div class="friend-view">
14
+ <div class="friend-list-container">
15
+ <div id="message-list"
16
+ :class="'friend-list' +
17
+ (uiStore.openSideBar ? ' open' : '') +
18
+ (showGroupAssist ? ' show' : '')">
19
+ <div>
20
+ <div class="base only">
21
+ <span>{{ $t('消息') }}</span>
22
+ <div style="flex: 1" />
23
+ <font-awesome-icon
24
+ :icon="['fas', 'clock-rotate-left']"
25
+ @click="openHistory" />
26
+ <font-awesome-icon :icon="['fas', 'trash-can']" @click="cleanList" />
27
+ </div>
28
+ <div class="small">
29
+ <span>{{ $t('消息') }}</span>
30
+ <div v-if="showGroupAssist"
31
+ style="margin-right: -5px;margin-left: 5px;"
32
+ @click="showGroupAssist = !showGroupAssist">
33
+ <font-awesome-icon :icon="['fas', 'angle-left']" />
34
+ </div>
35
+ <div @click="openLeftBar">
36
+ <font-awesome-icon :icon="['fas', 'bars-staggered']" />
37
+ </div>
38
+ </div>
39
+ </div>
40
+ <div id="message-list-body" class="robot-accordion-list">
41
+ <div v-for="bot in satoriLogins" :key="'bot-' + bot.selfId"
42
+ :class="['robot-accordion', { expanded: bot.selfId === activeBotId }]">
43
+ <div class="robot-accordion-header" @click="toggleRobot(bot)">
44
+ <img :src="bot.avatar || '/img/icons/icon.svg'" :alt="bot.name" @error="avatarError">
45
+ <div>
46
+ <span :title="bot.name">{{ bot.name }}</span>
47
+ <small>{{ bot.platform }}</small>
48
+ </div>
49
+ <font-awesome-icon :icon="['fas', bot.selfId === activeBotId ? 'angle-up' : 'angle-down']" />
50
+ </div>
51
+ <div v-if="bot.selfId === activeBotId" class="robot-accordion-content">
52
+ <div v-if="!showGroupAssist &&
53
+ !contactStore.systemNoticesList &&
54
+ (!contactStore.groupAssistList || contactStore.groupAssistList.length === 0) &&
55
+ contactStore.onMsgList.length === 0"
56
+ class="empty-state">
57
+ {{ $t('空') }}
58
+ </div>
59
+ <TransitionGroup
60
+ name="onmsg"
61
+ tag="div"
62
+ :class="uiStore.openSideBar ? ' open' : ''"
63
+ style="overflow-x: hidden">
64
+ <!-- 系统信息 -->
65
+ <FriendBody v-if="!showGroupAssist &&
66
+ contactStore.systemNoticesList &&
67
+ Object.keys(contactStore.systemNoticesList).length > 0"
68
+ key="inMessage--10000"
69
+ :select="chat.show.id === -10000"
70
+ :menu="menu.select && menu.select.user_id === -10000"
71
+ :data="{
72
+ user_id: -10000,
73
+ always_top: true,
74
+ nickname: $t('系统通知'),
75
+ remark: $t('系统通知'),
76
+ raw_msg: contactStore.systemNoticesList[0].comment
77
+ }"
78
+ @click="systemNoticeClick"
79
+ @contextmenu.prevent="systemNoticeMenuShow($event)"
80
+ @touchstart="systemNoticeMenuStart($event)"
81
+ @touchmove="showMenuMove"
82
+ @touchend="showMenuEnd" />
83
+ <!--- 群组消息 -->
84
+ <FriendBody
85
+ v-if="contactStore.groupAssistList && contactStore.groupAssistList.length > 0"
86
+ key="inMessage--10001"
87
+ :select="chat.show.id === -10001"
88
+ :data="{
89
+ user_id: -10001,
90
+ always_top: true,
91
+ nickname: $t('群收纳盒'),
92
+ remark: $t('群收纳盒'),
93
+ time: contactStore.groupAssistList[0].time,
94
+ raw_msg: contactStore.groupAssistList[0].group_name + ': ' +
95
+ (contactStore.groupAssistList[0].raw_msg_base ?? '')
96
+ }"
97
+ @click="showGroupAssistCheck" />
98
+ <!-- 其他消息 -->
99
+ <FriendBody
100
+ v-for="item in contactStore.onMsgList"
101
+ :key="'inMessage-' + (item.user_id ? item.user_id : item.group_id)"
102
+ :select="chat.show.id === item.user_id || (chat.show.id === item.group_id && chat.group_name != '')"
103
+ :menu="menu.select && menu.select == item"
104
+ :data="item"
105
+ from="message"
106
+ @contextmenu.prevent="listMenuShow($event, item)"
107
+ @click="userClick(item)"
108
+ @touchstart="showMenuStart($event, item)"
109
+ @touchmove="showMenuMove"
110
+ @touchend="showMenuEnd" />
111
+ </TransitionGroup>
112
+ </div>
113
+ </div>
114
+ </div>
115
+ </div>
116
+ <div id="group-assist-message-list"
117
+ :class="'friend-list group-assist-message-list' +
118
+ (uiStore.openSideBar ? ' open' : '') +
119
+ (showGroupAssist ? ' show' : '')">
120
+ <div>
121
+ <div class="base only">
122
+ <span style="cursor: pointer;"
123
+ @click="showGroupAssist = !showGroupAssist">
124
+ <font-awesome-icon style="margin-right: 5px;" :icon="['fas', 'angle-left']" />
125
+ {{ $t('群收纳盒') }}
126
+ </span>
127
+ <a v-if="contactStore.newMsgCount > 0">{{ contactStore.newMsgCount }}</a>
128
+ </div>
129
+ <div class="small">
130
+ <span style="cursor: pointer;">
131
+ {{ $t('群收纳盒') }}
132
+ <a v-if="contactStore.newMsgCount > 0">{{ contactStore.newMsgCount }}</a>
133
+ </span>
134
+ <div v-if="showGroupAssist"
135
+ style="margin-right: -5px;margin-left: 5px;"
136
+ @click="showGroupAssist = !showGroupAssist">
137
+ <font-awesome-icon :icon="['fas', 'angle-left']" />
138
+ </div>
139
+ <div @click="openLeftBar">
140
+ <font-awesome-icon :icon="['fas', 'bars-staggered']" />
141
+ </div>
142
+ </div>
143
+ </div>
144
+ <TransitionGroup
145
+ id="group-assist-message-list-body"
146
+ name="onmsg"
147
+ tag="div"
148
+ :class="uiStore.openSideBar ? ' open' : ''"
149
+ style="overflow-x: hidden">
150
+ <!-- 其他消息 -->
151
+ <FriendBody
152
+ v-for="item in contactStore.groupAssistList"
153
+ :key="'inMessage-' + (item.user_id ? item.user_id : item.group_id)"
154
+ :select="chat.show.id === item.user_id || (chat.show.id === item.group_id && chat.group_name != '')"
155
+ :menu="menu.select && menu.select == item"
156
+ :data="item"
157
+ from="message"
158
+ @contextmenu.prevent="listMenuShow($event, item)"
159
+ @click="userClick(item)"
160
+ @touchstart="showMenuStart($event, item)"
161
+ @touchmove="showMenuMove"
162
+ @touchend="showMenuEnd" />
163
+ </TransitionGroup>
164
+ </div>
165
+ </div>
166
+ <BcMenu :data="listMenu" name="messages-menu"
167
+ @close="listMenuClose">
168
+ <ul>
169
+ <li id="top" icon="fa-solid fa-thumbtack">
170
+ {{ $t('置顶') }}
171
+ </li>
172
+ <li id="canceltop" icon="fa-solid fa-grip-lines">
173
+ {{ $t('取消置顶') }}
174
+ </li>
175
+ <li id="remove" icon="fa-solid fa-trash-can">
176
+ {{ $t('删除') }}
177
+ </li>
178
+ <li id="readed" icon="fa-solid fa-check-to-slot">
179
+ {{ $t('标记已读') }}
180
+ </li>
181
+ <li id="read" icon="fa-solid fa-flag">
182
+ {{ $t('标记未读') }}
183
+ </li>
184
+ <li id="clear_system_notice" icon="fa-solid fa-broom">
185
+ {{ $t('清空通知') }}
186
+ </li>
187
+ </ul>
188
+ </BcMenu>
189
+ <div :class="'friend-list-space' + (uiStore.openSideBar ? ' open' : '')">
190
+ <div v-if="!loginInfo.status || chatStore.chatInfo.show.id == 0" class="ss-card">
191
+ <font-awesome-icon :icon="['fas', 'inbox']" />
192
+ <span>{{ $t('选择联系人开始聊天') }}</span>
193
+ </div>
194
+ <div v-else-if="chatStore.messageList.length > 0" class="ss-card cd">
195
+ <font-awesome-icon :icon="['fas', 'angles-right']" />
196
+ <span>(っ≧ω≦)っ</span>
197
+ <span>{{ $t('别划了别划了被看见了啦') }}</span>
198
+ </div>
199
+ </div>
200
+ </div>
201
+ </template>
202
+
203
+ <script setup lang="ts">
204
+ import { computed, ref, onMounted, markRaw, watch, nextTick } from 'vue'
205
+ import { i18n } from '../main'
206
+ import FriendBody from '../components/FriendBody.vue'
207
+ import BcMenu from 'vue3-bcui/packages/bc-menu'
208
+ import Menu from 'vue3-bcui/packages/bc-menu/index'
209
+ import Option from '../function/option'
210
+
211
+ import { useSettingsStore } from '../state/settings'
212
+ import {
213
+ UserFriendElem,
214
+ UserGroupElem,
215
+ } from '../function/elements/information'
216
+ import { PopInfo, PopType } from '../function/base'
217
+ import { MenuStatue } from 'vue3-bcui/packages/dist/types'
218
+ import { library } from '@fortawesome/fontawesome-svg-core'
219
+ import { login as loginInfo } from '../function/connect'
220
+ import { Connector, flushPendingBotEvents, loadContactsFromCache, restoreBotStateFromMessageCache } from '../function/connect'
221
+ import { getActiveBot, getLogins, setActiveBot } from '../function/satori'
222
+ import { getShowName, updateBaseOnMsgList } from '../function/utils/msgUtil'
223
+
224
+ import {
225
+ faThumbTack,
226
+ faTrashCan,
227
+ faCheckToSlot,
228
+ faGripLines,
229
+ faBroom,
230
+ } from '@fortawesome/free-solid-svg-icons'
231
+ import { Notify } from '../function/notify'
232
+ import { refreshFavicon } from '../function/favicon'
233
+ import { backend } from '../runtime/backend'
234
+ import History from '../components/History.vue'
235
+ import { normalizeSessionId } from '../function/utils/sessionUtil'
236
+ import { avatarError } from '../function/utils/avatarUtil'
237
+ import { useUIStore } from '../state/ui'
238
+ import { useAuthStore } from '../state/auth'
239
+ import { useContactStore } from '../state/contact'
240
+ import { useChatStore } from '../state/chat'
241
+
242
+ const $t = i18n.global.t
243
+
244
+ defineOptions({ name: 'VueMessages' })
245
+
246
+ const uiStore = useUIStore()
247
+ const authStore = useAuthStore()
248
+ const contactStore = useContactStore()
249
+ const chatStore = useChatStore()
250
+ const settingsStore = useSettingsStore()
251
+ const satoriLogins = ref<Array<{ platform: string; selfId: string; name: string; avatar?: string; status?: number; features?: string[] }>>(getLogins())
252
+ const activeBotId = ref(getActiveBot()?.selfId ?? loginInfo.selectedSatoriBot ?? '')
253
+
254
+ watch(() => loginInfo.satoriLogins, (list) => {
255
+ satoriLogins.value = list ?? []
256
+ if (activeBotId.value && contactStore.userList.length === 0) {
257
+ void loadContactsFromCache()
258
+ }
259
+ }, { immediate: true })
260
+
261
+ const currentBotName = computed(() => {
262
+ return satoriLogins.value.find((item) => item.selfId === activeBotId.value)?.name ?? ''
263
+ })
264
+
265
+ function backToRobots() {
266
+ snapshotCurrentBot()
267
+ activeBotId.value = ''
268
+ chatStore.messageList = []
269
+ chatStore.chatInfo.show.id = 0
270
+ }
271
+
272
+ function snapshotCurrentBot() {
273
+ const id = activeBotId.value
274
+ if (!id) return
275
+ contactStore.botStates.set(id, {
276
+ userList: [...contactStore.userList],
277
+ baseList: Array.from(contactStore.baseOnMsgList.entries()),
278
+ onMsgList: [...contactStore.onMsgList],
279
+ })
280
+ }
281
+
282
+ function restoreBotStateUi(bot: { platform: string; selfId: string }) {
283
+ const restored = contactStore.botStates.get(bot.selfId)
284
+ if (!restored) return
285
+ contactStore.baseOnMsgList.clear()
286
+ for (const [key, value] of restored.baseList) {
287
+ contactStore.baseOnMsgList.set(normalizeSessionId(key), value)
288
+ }
289
+ for (const item of restored.onMsgList) {
290
+ const id = String(item.user_id ?? item.group_id ?? '')
291
+ if (!id || id === '0') continue
292
+ contactStore.baseOnMsgList.set(
293
+ normalizeSessionId(id),
294
+ item as UserFriendElem & UserGroupElem,
295
+ )
296
+ }
297
+ contactStore.onMsgList = restored.onMsgList
298
+ }
299
+
300
+ function selectRobot(bot: { platform: string; selfId: string; name: string; avatar?: string; features?: string[] }) {
301
+ if (bot.selfId === activeBotId.value) return
302
+ snapshotCurrentBot()
303
+ activeBotId.value = bot.selfId
304
+ setActiveBot(bot.platform, bot.selfId)
305
+ loginInfo.uin = bot.selfId
306
+ loginInfo.nickname = bot.name
307
+ loginInfo.platform = bot.platform
308
+ authStore.loginInfo = {
309
+ ...authStore.loginInfo,
310
+ uin: bot.selfId,
311
+ user_id: bot.selfId,
312
+ nickname: bot.name,
313
+ platform: bot.platform,
314
+ avatar: bot.avatar,
315
+ satoriLogins: satoriLogins.value,
316
+ selectedSatoriBot: bot.selfId,
317
+ }
318
+ const saved = contactStore.botStates.get(bot.selfId)
319
+ if (saved) {
320
+ contactStore.userList = saved.userList
321
+ contactStore.baseOnMsgList.clear()
322
+ for (const [key, value] of saved.baseList) {
323
+ contactStore.baseOnMsgList.set(normalizeSessionId(key), value)
324
+ }
325
+ contactStore.onMsgList = saved.onMsgList
326
+ restoreBotStateFromMessageCache(bot.platform, bot.selfId)
327
+ restoreBotStateUi(bot)
328
+ flushPendingBotEvents(bot.platform, bot.selfId)
329
+ updateBaseOnMsgList()
330
+ void loadContactsFromCache()
331
+ } else {
332
+ contactStore.userList = []
333
+ contactStore.baseOnMsgList.clear()
334
+ contactStore.onMsgList = []
335
+ chatStore.messageList = []
336
+ chatStore.chatInfo.show.id = 0
337
+ restoreBotStateFromMessageCache(bot.platform, bot.selfId)
338
+ restoreBotStateUi(bot)
339
+ flushPendingBotEvents(bot.platform, bot.selfId)
340
+ updateBaseOnMsgList()
341
+ void loadContactsFromCache()
342
+ }
343
+ }
344
+
345
+ function toggleRobot(bot: { platform: string; selfId: string; name: string; avatar?: string; features?: string[] }) {
346
+ if (activeBotId.value === bot.selfId) {
347
+ backToRobots()
348
+ } else {
349
+ selectRobot(bot)
350
+ }
351
+ }
352
+ const props = defineProps<{ chat: any }>()
353
+ const emit = defineEmits<{
354
+ userClick: [data: any]
355
+ loadHistory: [data: any]
356
+ }>()
357
+
358
+ const trRead = ref(false)
359
+ const listMenu = ref<MenuStatue>({
360
+ show: false,
361
+ point: { x: 0, y: 0 },
362
+ })
363
+ const menu = Menu.append
364
+ const showMenu = ref(false)
365
+ const showGroupAssist = ref(false)
366
+
367
+ onMounted(() => {
368
+ library.add(faCheckToSlot, faThumbTack, faTrashCan, faGripLines, faBroom)
369
+ if (activeBotId.value && contactStore.userList.length === 0) {
370
+ void loadContactsFromCache()
371
+ }
372
+ })
373
+
374
+ /**
375
+ * 联系人点击事件
376
+ * @param data 联系人对象
377
+ */
378
+ function userClick(data: UserFriendElem & UserGroupElem) {
379
+ const id = data.user_id ? data.user_id : data.group_id
380
+ if (id === undefined || id === null || String(id) === '' || String(id) === '0') return
381
+ if (!trRead.value && id != props.chat.show.id) {
382
+ if (uiStore.openSideBar) {
383
+ openLeftBar()
384
+ }
385
+ const back = {
386
+ // 临时会话标志
387
+ temp: data.group_name == '' ? data.group_id : undefined,
388
+ type: data.user_id ? 'user' : 'group',
389
+ id: id,
390
+ name: getShowName(data.group_name || data.nickname, data.remark),
391
+ avatar: data.avatar || '/img/icons/icon.svg',
392
+ channel_id: data.channel_id ?? data.channelId,
393
+ guild_id: data.guild_id ?? data.guildId,
394
+ }
395
+ if (props.chat.id != back.id) {
396
+ // 更新聊天框
397
+ emit('userClick', back)
398
+ // 获取历史消息
399
+ if(!uiStore.nowGetHistory) {
400
+ emit('loadHistory', back)
401
+ }
402
+ }
403
+ // 清除新消息标记
404
+ const item = contactStore.baseOnMsgList.get(normalizeSessionId(id))
405
+ if(item) {
406
+ if(item.new_msg) {
407
+ item.new_msg = false
408
+ contactStore.newMsgCount--
409
+ }
410
+ item.highlight = undefined
411
+ contactStore.baseOnMsgList.set(normalizeSessionId(id), item)
412
+ // 关闭所有通知
413
+ new Notify().closeAll((item.group_id ?? item.user_id).toString())
414
+ }
415
+ }
416
+ }
417
+
418
+ /**
419
+ * 显示系统通知菜单
420
+ * @param event 鼠标事件
421
+ */
422
+ function systemNoticeMenuShow(event: Event) {
423
+ const info = menu.set('messages-menu', event as MouseEvent)
424
+ showMenu.value = false
425
+ info.list = ['clear_system_notice']
426
+ listMenu.value = info
427
+ menu.select = { user_id: -10000 }
428
+ }
429
+
430
+ /**
431
+ * 系统通知菜单长按开始
432
+ */
433
+ function systemNoticeMenuStart(event: TouchEvent) {
434
+ showMenuStart(event, { user_id: -10000 } as any)
435
+ }
436
+
437
+ /**
438
+ * 清空系统通知
439
+ */
440
+ function clearSystemNotices() {
441
+ contactStore.systemNoticesList = []
442
+ new PopInfo().add(
443
+ PopType.INFO,
444
+ $t('已清空系统通知'),
445
+ )
446
+ }
447
+
448
+ /**
449
+ * 系统通知点击事件
450
+ */
451
+ function systemNoticeClick() {
452
+ if (uiStore.openSideBar) {
453
+ openLeftBar()
454
+ }
455
+ const back = {
456
+ type: 'user',
457
+ id: -10000,
458
+ name: '系统消息',
459
+ }
460
+ emit('userClick', back)
461
+ }
462
+
463
+ /**
464
+ * 侧边栏操作
465
+ */
466
+ function openLeftBar() {
467
+ uiStore.openSideBar = !uiStore.openSideBar
468
+ }
469
+
470
+ /**
471
+ * 标记群组消息为已读
472
+ */
473
+ function readMsg(data: UserFriendElem & UserGroupElem) {
474
+ const id = data.group_id ? data.group_id : data.user_id
475
+ const item = contactStore.baseOnMsgList.get(normalizeSessionId(id))
476
+ if(item) {
477
+ if(item.new_msg) {
478
+ item.new_msg = false
479
+ contactStore.newMsgCount--
480
+ }
481
+ item.highlight = undefined
482
+ contactStore.baseOnMsgList.set(normalizeSessionId(id), item)
483
+ }
484
+ // pop
485
+ new PopInfo().add(
486
+ PopType.INFO,
487
+ $t('已标记为已读'),
488
+ )
489
+ }
490
+
491
+ /**
492
+ * 清空消息列表
493
+ */
494
+ function cleanList() {
495
+ // 刷新置顶列表
496
+ const info = settingsStore.sysConfig.top_info as {
497
+ [key: string]: number[]
498
+ } | null
499
+ contactStore.baseOnMsgList.clear()
500
+ contactStore.onMsgList = []
501
+ contactStore.groupAssistList = []
502
+ contactStore.systemNoticesList = undefined
503
+ contactStore.newMsgCount = 0
504
+ for (const state of contactStore.botStates.values()) {
505
+ state.baseList = []
506
+ state.onMsgList = []
507
+ }
508
+ if (info != null) {
509
+ const topList = info[authStore.loginInfo.uin]
510
+ if (topList !== undefined) {
511
+ contactStore.userList.forEach((item) => {
512
+ const id = Number(
513
+ item.user_id ? item.user_id : item.group_id,
514
+ )
515
+ if (topList.indexOf(id) >= 0) {
516
+ item.always_top = true
517
+ contactStore.baseOnMsgList.set(normalizeSessionId(id), item)
518
+ }
519
+ })
520
+ }
521
+ }
522
+ // 刷新 favicon
523
+ refreshFavicon()
524
+ }
525
+
526
+ /**
527
+ * 列表菜单关闭事件
528
+ * @param id 选择的菜单 ID
529
+ */
530
+ function listMenuClose(id: string) {
531
+ const menuEl = document.getElementById(
532
+ 'msg-menu-view-messages-menu',
533
+ )?.children[1] as HTMLDivElement
534
+ if (menuEl) {
535
+ setTimeout(() => {
536
+ menuEl.style.transition = 'transform .1s'
537
+ }, 200)
538
+ }
539
+ listMenu.value.show = false
540
+ const item = menu.select
541
+ if (id) {
542
+ switch (id) {
543
+ case 'read': {
544
+ if(!item.new_msg) {
545
+ item.new_msg = true
546
+ contactStore.newMsgCount++
547
+ }
548
+ break
549
+ }
550
+ case 'readed':
551
+ readMsg(item)
552
+ // 刷新 favicon
553
+ refreshFavicon()
554
+ break
555
+ case 'remove': {
556
+ const id = item.user_id ? item.user_id : item.group_id
557
+ contactStore.baseOnMsgList.delete(normalizeSessionId(id))
558
+ refreshFavicon()
559
+ break
560
+ }
561
+ case 'top':
562
+ saveTop(item, true)
563
+ break
564
+ case 'canceltop':
565
+ saveTop(item, false)
566
+ break
567
+ case 'clear_system_notice': {
568
+ clearSystemNotices()
569
+ break
570
+ }
571
+ }
572
+ }
573
+ menu.select = undefined
574
+ }
575
+
576
+ /**
577
+ * 保存置顶信息
578
+ * @param item 菜单选中项
579
+ * @param value 是否置顶
580
+ */
581
+ function saveTop(item: any, value: boolean) {
582
+ const id = authStore.loginInfo.uin
583
+ const upId = item.user_id ? item.user_id : item.group_id
584
+ // 完整的设置 JSON
585
+ let topInfo = settingsStore.sysConfig.top_info as {
586
+ [key: string]: number[]
587
+ }
588
+ if (topInfo == null || typeof topInfo !== 'object') {
589
+ topInfo = {}
590
+ }
591
+ // 本人的置顶信息
592
+ let topList = topInfo[id]
593
+ // 操作
594
+ if (value) {
595
+ if (topList) {
596
+ if (topList.indexOf(props.chat.show.id) < 0) {
597
+ topList.push(upId)
598
+ }
599
+ } else {
600
+ topList = [upId]
601
+ }
602
+ } else {
603
+ if (topList) {
604
+ topList.splice(topList.indexOf(upId), 1)
605
+ }
606
+ }
607
+ // 刷新设置
608
+ if (topList) {
609
+ topInfo[id] = topList
610
+ Option.save('top_info', topInfo)
611
+ }
612
+ // 为消息列表内的对象刷新置顶标志
613
+ item.always_top = value
614
+ // 刷新群收纳盒
615
+ if(item.group_id && settingsStore.sysConfig.bubble_sort_user) {
616
+ if(value) {
617
+ showGroupAssist.value = false
618
+ } else {
619
+ showGroupAssist.value = true
620
+ }
621
+ }
622
+ }
623
+
624
+ /**
625
+ * 显示列表菜单
626
+ * @param item 菜单内容
627
+ */
628
+ function listMenuShow(event: Event, item: UserFriendElem & UserGroupElem) {
629
+ const info = menu.set('messages-menu', event as MouseEvent)
630
+ listMenuShowRun(info, item)
631
+ }
632
+
633
+ function listMenuShowRun(info: any, item: UserFriendElem & UserGroupElem) {
634
+ // PS:这是触屏触发的标志,如果优先触发了 contextmenu 就不用触发触屏了
635
+ showMenu.value = false
636
+ info.list = ['top', 'remove']
637
+ // 置顶的不显示移除
638
+ if (item.always_top) {
639
+ info.list = ['canceltop']
640
+ }
641
+ if (item.new_msg) {
642
+ info.list.push('readed')
643
+ } else {
644
+ info.list.push('read')
645
+ }
646
+ listMenu.value = info
647
+ menu.select = item
648
+ // 出界处理
649
+ // 菜单显示后再测量,避免固定延迟
650
+ nextTick(() => {
651
+ const menuEl = document.getElementById(
652
+ 'msg-menu-view-messages-menu',
653
+ )?.children[1] as HTMLDivElement
654
+ if (menuEl) {
655
+ menuEl.style.transition = 'margin .2s, transform .1s'
656
+ const hight = menuEl.clientHeight
657
+ const top = menuEl.getBoundingClientRect().top
658
+ const docHight = document.documentElement.clientHeight
659
+ // 出界高度
660
+ const dtHight = hight + top - docHight + 20
661
+ if (dtHight > 0) {
662
+ menuEl.style.marginTop = docHight - hight - 30 + 'px'
663
+ }
664
+ }
665
+ })
666
+ }
667
+
668
+ /**
669
+ * 显示群收纳盒
670
+ */
671
+ function showGroupAssistCheck() {
672
+ // 只展开收纳盒,不再默认选中第一个群
673
+ showGroupAssist.value = !showGroupAssist.value
674
+ }
675
+
676
+ function showMenuStart(
677
+ event: TouchEvent,
678
+ item: UserFriendElem & UserGroupElem,
679
+ ) {
680
+ const info = {
681
+ show: true,
682
+ point: {
683
+ x: event.targetTouches[0].pageX,
684
+ y: event.targetTouches[0].pageY,
685
+ },
686
+ }
687
+ showMenu.value = true
688
+ setTimeout(() => {
689
+ if (showMenu.value) {
690
+ listMenuShowRun(info, item)
691
+ showMenu.value = false
692
+ }
693
+ }, 500)
694
+ }
695
+
696
+ function showMenuMove() {
697
+ showMenu.value = false
698
+ }
699
+
700
+ function showMenuEnd() {
701
+ showMenu.value = false
702
+ }
703
+
704
+ function openHistory() {
705
+ const popInfo = {
706
+ template: markRaw(History),
707
+ svg: 'clock-rotate-left',
708
+ title: $t('历史记录')
709
+ }
710
+ uiStore.popBoxList.push(popInfo)
711
+ }
712
+ </script>
713
+
714
+ <style>
715
+ .robot-item {
716
+ display: flex;
717
+ align-items: center;
718
+ gap: 8px;
719
+ padding: 10px 12px;
720
+ cursor: pointer;
721
+ border-left: 3px solid transparent;
722
+ }
723
+
724
+ .robot-item:hover {
725
+ background: var(--color-hover-bg, rgba(0, 0, 0, 0.04));
726
+ }
727
+
728
+ .robot-item.active {
729
+ border-left-color: var(--color-main, #3b82f6);
730
+ background: var(--color-active-bg, rgba(59, 130, 246, 0.08));
731
+ }
732
+
733
+ .robot-item img {
734
+ width: 32px;
735
+ height: 32px;
736
+ border-radius: 50%;
737
+ object-fit: cover;
738
+ }
739
+
740
+ .robot-item div {
741
+ display: flex;
742
+ flex-direction: column;
743
+ min-width: 0;
744
+ flex: 1;
745
+ overflow: hidden;
746
+ }
747
+
748
+ .robot-item span {
749
+ display: block;
750
+ font-size: 13px;
751
+ font-weight: 600;
752
+ max-width: 100%;
753
+ white-space: nowrap;
754
+ overflow: hidden;
755
+ text-overflow: ellipsis;
756
+ -webkit-mask-image: linear-gradient(to right, black 0%, black 70%, transparent 100%);
757
+ mask-image: linear-gradient(to right, black 0%, black 70%, transparent 100%);
758
+ }
759
+
760
+ .robot-item small {
761
+ font-size: 11px;
762
+ opacity: 0.6;
763
+ }
764
+
765
+ .robot-accordion-list {
766
+ height: 100%;
767
+ overflow-y: auto;
768
+ overflow-x: hidden;
769
+ }
770
+ .robot-accordion {
771
+ border-bottom: 1px solid var(--color-card-2, rgba(0, 0, 0, 0.08));
772
+ }
773
+ .robot-accordion-header {
774
+ display: flex;
775
+ align-items: center;
776
+ gap: 8px;
777
+ padding: 10px 12px;
778
+ cursor: pointer;
779
+ }
780
+ .robot-accordion-header:hover {
781
+ background: var(--color-hover-bg, rgba(0, 0, 0, 0.04));
782
+ }
783
+ .robot-accordion.expanded > .robot-accordion-header {
784
+ background: var(--color-active-bg, rgba(59, 130, 246, 0.08));
785
+ }
786
+ .robot-accordion-header img {
787
+ width: 32px;
788
+ height: 32px;
789
+ border-radius: 50%;
790
+ object-fit: cover;
791
+ flex-shrink: 0;
792
+ }
793
+ .robot-accordion-header > div {
794
+ display: flex;
795
+ flex-direction: column;
796
+ min-width: 0;
797
+ flex: 1;
798
+ overflow: hidden;
799
+ }
800
+ .robot-accordion-header span {
801
+ display: block;
802
+ font-size: 13px;
803
+ font-weight: 600;
804
+ max-width: 100%;
805
+ white-space: nowrap;
806
+ overflow: hidden;
807
+ text-overflow: ellipsis;
808
+ }
809
+ .robot-accordion-header small {
810
+ font-size: 11px;
811
+ opacity: 0.6;
812
+ }
813
+ .robot-accordion-header > svg {
814
+ opacity: 0.7;
815
+ flex-shrink: 0;
816
+ }
817
+ .robot-accordion-content {
818
+ padding: 2px 0 6px;
819
+ }
820
+ .empty-state {
821
+ display: flex;
822
+ align-items: center;
823
+ justify-content: center;
824
+ padding: 40px 0;
825
+ color: var(--color-font-2, #888);
826
+ opacity: 0.65;
827
+ }
828
+
829
+ .friend-list > div:first-child > div.base > span {
830
+ min-width: 0;
831
+ overflow: hidden;
832
+ white-space: nowrap;
833
+ text-overflow: clip;
834
+ -webkit-mask-image: linear-gradient(to right, black 0%, black 65%, transparent 100%);
835
+ mask-image: linear-gradient(to right, black 0%, black 65%, transparent 100%);
836
+ }
837
+
838
+ .friend-list-container {
839
+ overflow: hidden;
840
+ display: flex;
841
+ }
842
+
843
+ .onmsg-enter-active,
844
+ .onmsg-leave-active,
845
+ .onmsg-move {
846
+ transition: transform 0.4s;
847
+ }
848
+
849
+ .menu div.item > a {
850
+ font-size: 0.9rem !important;
851
+ }
852
+ .menu div.item > svg {
853
+ margin: 3px 10px 3px 0 !important;
854
+ font-size: 1rem !important;
855
+ }
856
+
857
+ .msg-menu-bg {
858
+ background: transparent !important;
859
+ }
860
+
861
+ @media (max-width: 700px) {
862
+ .friend-list-container {
863
+ overflow: unset;
864
+ }
865
+ .menu {
866
+ width: 140px !important;
867
+ }
868
+ }
869
+
870
+ @media (max-width: 500px) {
871
+ .friend-list-container {
872
+ overflow: hidden;
873
+ }
874
+ }
875
+ </style>