11<script setup lang="ts">
22import { StateEffect } from ' @codemirror/state'
33import { EditorView } from ' @codemirror/view'
4- import { ArrowUpDown , BookOpen , ChevronRight , ChevronsUpDown , Clock , Cloud , CloudAlert , CloudCheck , CloudOff , Columns2 , Eye , FileText , Keyboard , ListTree , Loader2 , LogIn , Monitor , Moon , PenLine , Pilcrow , Search , Share2 , Smartphone , Sun , Type , User } from ' @lucide/vue'
4+ import { ArrowUpDown , BookOpen , ChevronRight , ChevronsUpDown , Clock , Columns2 , Ellipsis , Eye , FileText , Keyboard , ListTree , LogIn , Monitor , Moon , PenLine , Pilcrow , Search , Share2 , Smartphone , Sun , Type , User } from ' @lucide/vue'
55import {
66 Popover ,
77 PopoverContent ,
@@ -13,23 +13,21 @@ import {
1313 TooltipProvider ,
1414 TooltipTrigger ,
1515} from ' @/components/ui/tooltip'
16- import { useSyncStatusMeta } from ' @/composables/useSyncStatusMeta'
16+ import { useSyncFooterMeta } from ' @/composables/useSyncStatusMeta'
1717import { isAccountUiEnabled } from ' @/services/account/config'
1818import { isShareUiEnabled } from ' @/services/share/client'
1919import { isSyncUiEnabled } from ' @/services/sync/client'
2020import { useAuthStore } from ' @/stores/auth'
2121import { useEditorStore } from ' @/stores/editor'
2222import { usePostStore } from ' @/stores/post'
2323import { useRenderStore } from ' @/stores/render'
24- import { useSyncStore } from ' @/stores/sync'
2524import { useUIStore } from ' @/stores/ui'
2625
2726const renderStore = useRenderStore ()
2827const editorStore = useEditorStore ()
2928const postStore = usePostStore ()
3029const uiStore = useUIStore ()
3130const authStore = useAuthStore ()
32- const syncStore = useSyncStore ()
3331const { readingTime } = storeToRefs (renderStore )
3432const { editor } = storeToRefs (editorStore )
3533const { currentPost } = storeToRefs (postStore )
@@ -39,35 +37,35 @@ const { isLoggedIn } = storeToRefs(authStore)
3937const showAccountUi = isAccountUiEnabled ()
4038const showSyncUi = isSyncUiEnabled ()
4139const showShareUi = isShareUiEnabled ()
42- const { isSyncing, syncState } = storeToRefs (syncStore )
43- const { syncStatusMeta, syncTooltip } = useSyncStatusMeta ()
40+ const { syncFooterIcon, syncFooterIconClass, syncTooltip } = useSyncFooterMeta ()
41+
42+ const isMoreOpen = ref (false )
4443
4544const accountTooltip = computed (() => {
4645 if (! isLoggedIn .value )
4746 return ` 登录账户 `
4847 return ` 账户 @${authStore .user ?.login ?? ' ' } `
4948})
5049
51- const syncFooterIcon = computed (() => {
52- if (! isLoggedIn .value )
53- return Cloud
54- if (isSyncing .value || syncState .value === ` syncing ` )
55- return Loader2
56- switch (syncState .value ) {
57- case ` synced ` :
58- return CloudCheck
59- case ` error ` :
60- return CloudAlert
61- default :
62- return CloudOff
63- }
64- })
50+ function openAccountDialog() {
51+ isMoreOpen .value = false
52+ uiStore .toggleShowAccountDialog (true )
53+ }
6554
66- const syncFooterIconClass = computed (() => {
67- if (! isLoggedIn .value )
68- return ` `
69- return syncStatusMeta .value .footerIconClass
70- })
55+ function openSyncDialog() {
56+ isMoreOpen .value = false
57+ uiStore .toggleShowSyncDialog (true )
58+ }
59+
60+ function openShareDialog() {
61+ isMoreOpen .value = false
62+ uiStore .openShareDialog ()
63+ }
64+
65+ function toggleTheme() {
66+ isMoreOpen .value = false
67+ uiStore .toggleDark ()
68+ }
7169
7270// 相对时间格式化(复用)
7371function formatRelativeTime(date : Date | string ) {
@@ -655,16 +653,16 @@ const showDeviceToggle = computed(() => viewMode.value !== `edit` && !isMobile.v
655653
656654 <span class =" hidden text-border sm:block" >·</span >
657655
658- <!-- 账户 & 同步 & 分享 & 主题 -->
659- <div class =" flex items-center gap-0.5" >
656+ <!-- 账户 & 同步 & 分享 & 主题(桌面端) -->
657+ <div class =" hidden items-center gap-0.5 sm:flex " >
660658 <template v-if =" showAccountUi " >
661659 <Tooltip >
662660 <TooltipTrigger as-child>
663661 <button
664662 aria-label =" 账户"
665663 class =" flex cursor-pointer items-center rounded-md p-1.5 transition-colors hover:bg-accent hover:text-foreground"
666664 :class =" isLoggedIn ? 'text-primary' : ''"
667- @click =" uiStore.toggleShowAccountDialog(true) "
665+ @click =" openAccountDialog "
668666 >
669667 <img
670668 v-if =" isLoggedIn && authStore.user?.avatar"
@@ -688,8 +686,7 @@ const showDeviceToggle = computed(() => viewMode.value !== `edit` && !isMobile.v
688686 <button
689687 aria-label =" 云同步"
690688 class =" flex cursor-pointer items-center rounded-md p-1.5 transition-colors hover:bg-accent hover:text-foreground"
691- :class =" isLoggedIn ? 'text-primary' : ''"
692- @click =" uiStore.toggleShowSyncDialog(true)"
689+ @click =" openSyncDialog"
693690 >
694691 <component
695692 :is =" syncFooterIcon"
@@ -710,7 +707,7 @@ const showDeviceToggle = computed(() => viewMode.value !== `edit` && !isMobile.v
710707 <button
711708 aria-label =" 分享预览"
712709 class =" flex cursor-pointer items-center rounded-md p-1.5 transition-colors hover:bg-accent hover:text-foreground"
713- @click =" uiStore. openShareDialog() "
710+ @click =" openShareDialog"
714711 >
715712 <Share2 class="size-4" />
716713 </button >
@@ -724,9 +721,10 @@ const showDeviceToggle = computed(() => viewMode.value !== `edit` && !isMobile.v
724721 <Tooltip >
725722 <TooltipTrigger as-child>
726723 <button
724+ aria-label =" 切换深色模式"
727725 class =" flex cursor-pointer items-center rounded-md p-1.5 transition-colors hover:bg-accent hover:text-foreground"
728726 :class =" isDark ? 'text-foreground' : ''"
729- @click =" uiStore.toggleDark() "
727+ @click =" toggleTheme "
730728 >
731729 <Moon v-if =" isDark " class="size-4" />
732730 <Sun v-else class="size-4" />
@@ -737,6 +735,63 @@ const showDeviceToggle = computed(() => viewMode.value !== `edit` && !isMobile.v
737735 </TooltipContent >
738736 </Tooltip >
739737 </div >
738+
739+ <!-- 移动端:更多操作 -->
740+ <Popover v-model :open =" isMoreOpen " >
741+ <PopoverTriggerPrimitive as-child>
742+ <button
743+ aria-label =" 更多操作"
744+ class =" flex cursor-pointer items-center rounded-md p-1.5 transition-colors hover:bg-accent hover:text-foreground sm:hidden"
745+ >
746+ <Ellipsis class="size-4" />
747+ </button >
748+ </PopoverTriggerPrimitive >
749+ <PopoverContent side="top" :side-offset =" 8 " align="end" class="w-48 p-1">
750+ <button
751+ v-if =" showAccountUi"
752+ class =" flex w-full cursor-pointer items-center gap-2 rounded-md px-2.5 py-2 text-left text-xs transition-colors hover:bg-accent"
753+ @click =" openAccountDialog"
754+ >
755+ <img
756+ v-if =" isLoggedIn && authStore.user?.avatar"
757+ :src =" authStore.user.avatar"
758+ :alt =" authStore.user.login"
759+ class =" size-4 rounded-full"
760+ >
761+ <User v-else-if =" isLoggedIn " class="size-4 shrink-0" />
762+ <LogIn v-else class="size-4 shrink-0" />
763+ <span class =" min-w-0 flex-1 truncate" >{{ accountTooltip }}</span >
764+ </button >
765+ <button
766+ v-if =" showSyncUi"
767+ class =" flex w-full cursor-pointer items-center gap-2 rounded-md px-2.5 py-2 text-left text-xs transition-colors hover:bg-accent"
768+ @click =" openSyncDialog"
769+ >
770+ <component
771+ :is =" syncFooterIcon"
772+ class =" size-4 shrink-0"
773+ :class =" syncFooterIconClass"
774+ />
775+ <span >{{ isLoggedIn ? syncTooltip : '云同步' }}</span >
776+ </button >
777+ <button
778+ v-if =" showShareUi"
779+ class =" flex w-full cursor-pointer items-center gap-2 rounded-md px-2.5 py-2 text-left text-xs transition-colors hover:bg-accent"
780+ @click =" openShareDialog"
781+ >
782+ <Share2 class="size-4 shrink-0" />
783+ <span >分享预览</span >
784+ </button >
785+ <button
786+ class =" flex w-full cursor-pointer items-center gap-2 rounded-md px-2.5 py-2 text-left text-xs transition-colors hover:bg-accent"
787+ @click =" toggleTheme"
788+ >
789+ <Moon v-if =" isDark " class="size-4 shrink-0" />
790+ <Sun v-else class="size-4 shrink-0" />
791+ <span >{{ isDark ? '浅色模式' : '深色模式' }}</span >
792+ </button >
793+ </PopoverContent >
794+ </Popover >
740795 </div >
741796 </TooltipProvider >
742797 </footer >
0 commit comments