index.vue 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. <script setup lang="ts">
  2. import type { HTMLAttributes } from 'vue'
  3. import { cn } from '@/utils'
  4. import eventBus from '@/utils/eventBus'
  5. import Profile from './profile.vue'
  6. const props = withDefaults(defineProps<{
  7. onlyAvatar?: boolean
  8. dropdownAlign?: 'start' | 'center' | 'end'
  9. dropdownSide?: 'left' | 'right' | 'top' | 'bottom'
  10. buttonVariant?: 'secondary' | 'ghost'
  11. class?: HTMLAttributes['class']
  12. }>(), {
  13. dropdownAlign: 'end',
  14. dropdownSide: 'right',
  15. buttonVariant: 'ghost',
  16. })
  17. const router = useRouter()
  18. const settingsStore = useSettingsStore()
  19. const userStore = useUserStore()
  20. const isProfileShow = ref(false)
  21. </script>
  22. <template>
  23. <FaDropdown
  24. :align="dropdownAlign" :side="dropdownSide" :items="[
  25. [
  26. { label: settingsStore.settings.home.title, icon: 'i-mdi:home', handle: () => router.push({ path: settingsStore.settings.home.fullPath }), hide: !settingsStore.settings.home.enable },
  27. { label: '个人设置', icon: 'i-mdi:account', handle: () => isProfileShow = true },
  28. ],
  29. [
  30. { label: '快捷键介绍', icon: 'i-mdi:keyboard', handle: () => eventBus.emit('global-hotkeys-intro-toggle'), hide: settingsStore.mode !== 'pc' },
  31. ],
  32. [
  33. { label: '退出登录', icon: 'i-mdi:logout', handle: () => userStore.logout(settingsStore.settings.home.fullPath) },
  34. ],
  35. ]" class="flex-center"
  36. >
  37. <template #header>
  38. <div class="space-y-2">
  39. <div class="text-xs text-secondary-foreground/50 font-light">
  40. 当前登录账号
  41. </div>
  42. <div class="flex-center-start gap-2">
  43. <FaAvatar :src="userStore.avatar" :fallback="userStore.account.slice(0, 5)" shape="square" />
  44. <div class="space-y-1">
  45. <div class="text-base lh-none">
  46. {{ userStore.account }}
  47. </div>
  48. <div class="text-xs text-secondary-foreground/50 font-normal">
  49. [ 这里可以显示邮箱 ]
  50. </div>
  51. </div>
  52. </div>
  53. </div>
  54. </template>
  55. <FaButton
  56. :variant="buttonVariant" :class="cn('flex-center gap-1 p-2', {
  57. 'size-8 p-1': onlyAvatar,
  58. }, props.class)"
  59. >
  60. <FaAvatar :src="userStore.avatar" :class="cn('size-6', { 'size-full': onlyAvatar })">
  61. <FaIcon name="i-carbon:user-avatar-filled" class="size-6 text-secondary-foreground/50" />
  62. </FaAvatar>
  63. <div v-if="!onlyAvatar" class="min-w-0 flex-center-between flex-1 gap-2">
  64. <div class="flex-1 truncate text-start">
  65. {{ userStore.account }}
  66. </div>
  67. <FaIcon name="i-material-symbols:expand-all-rounded" />
  68. </div>
  69. </FaButton>
  70. </FaDropdown>
  71. <FaModal v-model="isProfileShow" align-center :header="false" :footer="false" :close-on-click-overlay="false" :close-on-press-escape="false" class="h-500px max-w-xl overflow-hidden" content-class="min-h-full p-0 flex">
  72. <Profile />
  73. </FaModal>
  74. </template>