index.vue 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. <template>
  2. <div class="navbar">
  3. <div class="left-side">
  4. <a-space>
  5. <img alt="logo"
  6. src="//p3-armor.byteimg.com/tos-cn-i-49unhts6dw/dfdba5317c0c20ce20e64fac803d52bc.svg~tplv-49unhts6dw-image.image" />
  7. <a-typography-title :style="{ margin: 0, fontSize: '18px' }" :heading="5">
  8. Molilian
  9. </a-typography-title>
  10. <icon-menu-fold v-if="!topMenu && appStore.device === 'mobile'" style="font-size: 22px; cursor: pointer"
  11. @click="toggleDrawerMenu" />
  12. </a-space>
  13. </div>
  14. <div class="center-side">
  15. <Menu v-if="topMenu" />
  16. </div>
  17. <ul class="right-side">
  18. <li>
  19. <a-tooltip :content="$t('settings.search')">
  20. <a-button class="nav-btn" type="outline" :shape="'circle'">
  21. <template #icon>
  22. <icon-search />
  23. </template>
  24. </a-button>
  25. </a-tooltip>
  26. </li>
  27. <li>
  28. <a-tooltip :content="$t('settings.language')">
  29. <a-button class="nav-btn" type="outline" :shape="'circle'" @click="setDropDownVisible">
  30. <template #icon>
  31. <icon-language />
  32. </template>
  33. </a-button>
  34. </a-tooltip>
  35. <a-dropdown trigger="click" @select="changeLocale as any">
  36. <div ref="triggerBtn" class="trigger-btn"></div>
  37. <template #content>
  38. <a-doption v-for="item in locales" :key="item.value" :value="item.value">
  39. <template #icon>
  40. <icon-check v-show="item.value === currentLocale" />
  41. </template>
  42. {{ item.label }}
  43. </a-doption>
  44. </template>
  45. </a-dropdown>
  46. </li>
  47. <li>
  48. <a-tooltip :content="theme === 'light'
  49. ? $t('settings.navbar.theme.toDark')
  50. : $t('settings.navbar.theme.toLight')
  51. ">
  52. <a-button class="nav-btn" type="outline" :shape="'circle'" @click="handleToggleTheme">
  53. <template #icon>
  54. <icon-moon-fill v-if="theme === 'dark'" />
  55. <icon-sun-fill v-else />
  56. </template>
  57. </a-button>
  58. </a-tooltip>
  59. </li>
  60. <li>
  61. <a-tooltip :content="$t('settings.navbar.alerts')">
  62. <div class="message-box-trigger">
  63. <a-badge :count="9" dot>
  64. <a-button class="nav-btn" type="outline" :shape="'circle'" @click="setPopoverVisible">
  65. <icon-notification />
  66. </a-button>
  67. </a-badge>
  68. </div>
  69. </a-tooltip>
  70. <a-popover trigger="click" :arrow-style="{ display: 'none' }"
  71. :content-style="{ padding: 0, minWidth: '400px' }" content-class="message-popover">
  72. <div ref="refBtn" class="ref-btn"></div>
  73. <template #content>
  74. <message-box />
  75. </template>
  76. </a-popover>
  77. </li>
  78. <li>
  79. <a-tooltip :content="isFullscreen
  80. ? $t('settings.navbar.screen.toExit')
  81. : $t('settings.navbar.screen.toFull')
  82. ">
  83. <a-button class="nav-btn" type="outline" :shape="'circle'" @click="toggleFullScreen">
  84. <template #icon>
  85. <icon-fullscreen-exit v-if="isFullscreen" />
  86. <icon-fullscreen v-else />
  87. </template>
  88. </a-button>
  89. </a-tooltip>
  90. </li>
  91. <li>
  92. <a-tooltip :content="$t('settings.title')">
  93. <a-button class="nav-btn" type="outline" :shape="'circle'" @click="setVisible">
  94. <template #icon>
  95. <icon-settings />
  96. </template>
  97. </a-button>
  98. </a-tooltip>
  99. </li>
  100. <li>
  101. <a-dropdown trigger="click">
  102. <a-avatar :size="32" :style="{ marginRight: '8px', cursor: 'pointer' }">
  103. <img alt="avatar" :src="avatar" />
  104. </a-avatar>
  105. <template #content>
  106. <a-doption>
  107. <a-space @click="$router.push({ name: 'Info' })">
  108. <icon-user />
  109. <span>
  110. {{ $t('messageBox.userCenter') }}
  111. </span>
  112. </a-space>
  113. </a-doption>
  114. <a-doption>
  115. <a-space @click="$router.push({ name: 'Setting' })">
  116. <icon-settings />
  117. <span>
  118. {{ $t('messageBox.userSettings') }}
  119. </span>
  120. </a-space>
  121. </a-doption>
  122. <a-doption>
  123. <a-space @click="handleLogout">
  124. <icon-export />
  125. <span>
  126. {{ $t('messageBox.logout') }}
  127. </span>
  128. </a-space>
  129. </a-doption>
  130. </template>
  131. </a-dropdown>
  132. </li>
  133. </ul>
  134. </div>
  135. </template>
  136. <script lang="ts" setup>
  137. import { computed, ref, inject } from 'vue';
  138. import { useDark, useToggle, useFullscreen } from '@vueuse/core';
  139. import { useAppStore, useUserStore } from '@/store';
  140. import { LOCALE_OPTIONS } from '@/locale';
  141. import useLocale from '@/hooks/locale';
  142. import useUser from '@/hooks/user';
  143. import Menu from '@/components/menu/index.vue';
  144. import MessageBox from '../message-box/index.vue';
  145. const appStore = useAppStore();
  146. const userStore = useUserStore();
  147. const { logout } = useUser();
  148. const { changeLocale, currentLocale } = useLocale();
  149. const { isFullscreen, toggle: toggleFullScreen } = useFullscreen();
  150. const locales = [...LOCALE_OPTIONS];
  151. const avatar = computed(() => {
  152. return userStore.avatar;
  153. });
  154. const theme = computed(() => {
  155. return appStore.theme;
  156. });
  157. const topMenu = computed(() => appStore.topMenu && appStore.menu);
  158. const isDark = useDark({
  159. selector: 'body',
  160. attribute: 'arco-theme',
  161. valueDark: 'dark',
  162. valueLight: 'light',
  163. storageKey: 'arco-theme',
  164. onChanged(dark: boolean) {
  165. // overridden default behavior
  166. appStore.toggleTheme(dark);
  167. },
  168. });
  169. const toggleTheme = useToggle(isDark);
  170. const handleToggleTheme = () => {
  171. toggleTheme();
  172. };
  173. const setVisible = () => {
  174. appStore.updateSettings({ globalSettings: true });
  175. };
  176. const refBtn = ref();
  177. const triggerBtn = ref();
  178. const setPopoverVisible = () => {
  179. const event = new MouseEvent('click', {
  180. view: window,
  181. bubbles: true,
  182. cancelable: true,
  183. });
  184. refBtn.value.dispatchEvent(event);
  185. };
  186. const handleLogout = () => {
  187. logout();
  188. };
  189. const setDropDownVisible = () => {
  190. const event = new MouseEvent('click', {
  191. view: window,
  192. bubbles: true,
  193. cancelable: true,
  194. });
  195. triggerBtn.value.dispatchEvent(event);
  196. };
  197. const toggleDrawerMenu = inject('toggleDrawerMenu') as () => void;
  198. </script>
  199. <style scoped lang="less">
  200. .navbar {
  201. display: flex;
  202. justify-content: space-between;
  203. height: 100%;
  204. background-color: var(--color-bg-2);
  205. border-bottom: 1px solid var(--color-border);
  206. }
  207. .left-side {
  208. display: flex;
  209. align-items: center;
  210. padding-left: 20px;
  211. }
  212. .center-side {
  213. flex: 1;
  214. }
  215. .right-side {
  216. display: flex;
  217. padding-right: 20px;
  218. list-style: none;
  219. :deep(.locale-select) {
  220. border-radius: 20px;
  221. }
  222. li {
  223. display: flex;
  224. align-items: center;
  225. padding: 0 10px;
  226. }
  227. a {
  228. color: var(--color-text-1);
  229. text-decoration: none;
  230. }
  231. .nav-btn {
  232. border-color: rgb(var(--gray-2));
  233. color: rgb(var(--gray-8));
  234. font-size: 16px;
  235. }
  236. .trigger-btn,
  237. .ref-btn {
  238. position: absolute;
  239. bottom: 14px;
  240. }
  241. .trigger-btn {
  242. margin-left: 14px;
  243. }
  244. }
  245. </style>
  246. <style lang="less">
  247. .message-popover {
  248. .arco-popover-content {
  249. margin-top: 0;
  250. }
  251. }
  252. </style>