feat(Dock): add config to move back-to-top or refresh button to dock

This commit is contained in:
Hakadao
2024-05-26 21:38:22 +08:00
parent 19f4b6aed2
commit 2250eefa09
9 changed files with 138 additions and 65 deletions

View File

@@ -92,6 +92,7 @@ settings:
dock_content_adjustment: Dock 内容调整
dock_content_adjustment_desc: 第一个激活的 Dock 项的页面将会是启动页面
disable_light_dark_mode_switcher: 禁用亮/暗色模式切换按钮
move_back_to_top_and_refresh_to_dock: 将返回顶部和刷新按钮移动到 Dock 栏
# Appearance
theme: 主题

View File

@@ -92,6 +92,7 @@ settings:
dock_content_adjustment: Dock 內容調整
dock_content_adjustment_desc: 第一個啓用的 Dock 項目的頁面將是起始頁面
disable_light_dark_mode_switcher: 停用淺/深色模式切換按鈕
move_back_to_top_and_refresh_to_dock: 將返回頂部和重新整理按鈕移動到 Dock
# Appearance
theme: 主題

View File

@@ -92,6 +92,7 @@ settings:
dock_content_adjustment: Dock content adjustment
dock_content_adjustment_desc: The page of the first activated dock item will be the startup page
disable_light_dark_mode_switcher: Disable light/dark mode switcher
move_back_to_top_and_refresh_to_dock: Move the back-to-top and refresh buttons to the dock
# Appearance
theme: Theme

View File

@@ -92,6 +92,7 @@ settings:
dock_content_adjustment: Dock 內容調整
dock_content_adjustment_desc: 第一個啓用嘅 Dock 項個頁面會係開始頁面
disable_light_dark_mode_switcher: 閂咗淺/深色主題切換粒掣
move_back_to_top_and_refresh_to_dock: 將返去頂部同重新整理粒掣擺到落 Dock 度
# Appearance
theme: 色系

View File

@@ -1,4 +1,5 @@
<script setup lang="ts">
import { useBewlyApp } from '~/composables/useAppProvider'
import { useDark } from '~/composables/useDark'
import { AppPage } from '~/enums/appEnums'
import { settings } from '~/logic'
@@ -8,19 +9,15 @@ import { useMainStore } from '~/stores/mainStore'
import Tooltip from '../Tooltip.vue'
import type { HoveringDockItem } from './types'
defineProps<{ activatedPage: AppPage }>()
defineProps<{
activatedPage: AppPage
}>()
const emit = defineEmits(['change-page', 'settings-visibility-change'])
const mainStore = useMainStore()
const { isDark, toggleDark } = useDark()
const hideDock = ref<boolean>(false)
const hoveringDockItem = reactive<HoveringDockItem>({
themeMode: false,
settings: false,
})
const currentDockItems = ref<DockItem[]>([])
const { reachTop, handleBackToTop, handlePageRefresh } = useBewlyApp()
const tooltipPlacement = computed(() => {
if (settings.value.dockPosition === 'left')
@@ -32,6 +29,13 @@ const tooltipPlacement = computed(() => {
return 'right'
})
const hideDock = ref<boolean>(false)
const hoveringDockItem = reactive<HoveringDockItem>({
themeMode: false,
settings: false,
})
const currentDockItems = ref<DockItem[]>([])
watch(() => settings.value.autoHideDock, (newValue) => {
hideDock.value = newValue
})
@@ -73,6 +77,13 @@ function toggleDockHide(hide: boolean) {
else
hideDock.value = false
}
function handleBackToTopOrRefresh() {
if (reachTop.value)
handlePageRefresh.value?.()
else
handleBackToTop()
}
</script>
<template>
@@ -98,68 +109,84 @@ function toggleDockHide(hide: boolean) {
bottom: settings.dockPosition === 'bottom',
hide: hideDock,
}"
style="backdrop-filter: var(--bew-filter-glass-1);"
absolute duration-300 ease-in-out transform-gpu
p-2 m-2 bg="$bew-content-2 dark:$bew-elevated-1" flex="~ col gap-2 shrink-0"
rounded="60px" border="1px $bew-border-color"
shadow="$bew-shadow-2"
@mouseenter="toggleDockHide(false)"
@mouseleave="toggleDockHide(true)"
>
<template v-for="dockItem in currentDockItems" :key="dockItem.page">
<Tooltip :content="$t(dockItem.i18nKey)" :placement="tooltipPlacement">
<div
class="dock-content-inner"
>
<template v-for="dockItem in currentDockItems" :key="dockItem.page">
<Tooltip :content="$t(dockItem.i18nKey)" :placement="tooltipPlacement">
<button
class="dock-item group"
:class="{ active: activatedPage === dockItem.page }"
@click="emit('change-page', dockItem.page)"
>
<div
v-show="activatedPage !== dockItem.page"
:class="dockItem.icon"
text-xl
/>
<div
v-show="activatedPage === dockItem.page"
:class="dockItem.iconActivated"
text-xl
/>
</button>
</Tooltip>
</template>
<!-- dividing line -->
<div class="divider" />
<Tooltip
v-if="!settings.disableLightDarkModeSwitcherOnDock"
:content="isDark ? $t('dock.dark_mode') : $t('dock.light_mode')" :placement="tooltipPlacement"
>
<button
class="dock-item group"
:class="{ active: activatedPage === dockItem.page }"
@click="emit('change-page', dockItem.page)"
class="dock-item"
@click="toggleDark"
@mouseenter="hoveringDockItem.themeMode = true"
@mouseleave="hoveringDockItem.themeMode = false"
>
<div
v-show="activatedPage !== dockItem.page"
:class="dockItem.icon"
text-xl
/>
<div
v-show="activatedPage === dockItem.page"
:class="dockItem.iconActivated"
text-xl
/>
<Transition name="fade">
<div v-show="hoveringDockItem.themeMode" absolute>
<div v-if="isDark" i-line-md:sunny-outline-to-moon-loop-transition text-xl />
<div v-else i-line-md:moon-alt-to-sunny-outline-loop-transition text-xl />
</div>
</Transition>
<Transition name="fade">
<div v-show="!hoveringDockItem.themeMode" absolute>
<div v-if="isDark" i-line-md:sunny-outline-to-moon-transition text-xl />
<div v-else i-line-md:moon-to-sunny-outline-transition text-xl />
</div>
</Transition>
</button>
</Tooltip>
</template>
<!-- dividing line -->
<div class="divider" />
<Tooltip :content="$t('dock.settings')" :placement="tooltipPlacement">
<button class="dock-item" @click="emit('settings-visibility-change')">
<div i-mingcute:settings-3-line text-xl />
</button>
</Tooltip>
</div>
<Tooltip
v-if="!settings.disableLightDarkModeSwitcherOnDock"
:content="isDark ? $t('dock.dark_mode') : $t('dock.light_mode')" :placement="tooltipPlacement"
<button
v-if="settings.moveBackToTopOrRefreshButtonToDock && activatedPage !== AppPage.Search"
class="back-to-top-or-refresh-btn"
@click="handleBackToTopOrRefresh"
>
<button
class="dock-item"
@click="toggleDark"
@mouseenter="hoveringDockItem.themeMode = true"
@mouseleave="hoveringDockItem.themeMode = false"
>
<Transition name="fade">
<div v-show="hoveringDockItem.themeMode" absolute>
<div v-if="isDark" i-line-md:sunny-outline-to-moon-loop-transition text-xl />
<div v-else i-line-md:moon-alt-to-sunny-outline-loop-transition text-xl />
</div>
</Transition>
<Transition name="fade">
<div v-show="!hoveringDockItem.themeMode" absolute>
<div v-if="isDark" i-line-md:sunny-outline-to-moon-transition text-xl />
<div v-else i-line-md:moon-to-sunny-outline-transition text-xl />
</div>
</Transition>
</button>
</Tooltip>
<Tooltip :content="$t('dock.settings')" :placement="tooltipPlacement">
<button class="dock-item" @click="emit('settings-visibility-change')">
<div i-mingcute:settings-3-line text-xl />
</button>
</Tooltip>
<Transition name="fade">
<div
v-if="reachTop" i-line-md:rotate-270
absolute text-xl rotate-90
/>
<div
v-else i-line-md:arrow-small-up
absolute text-xl
/>
</Transition>
</button>
</div>
</aside>
</template>
@@ -190,6 +217,8 @@ function toggleDockHide(hide: boolean) {
}
.dock-content {
--at-apply: absolute flex justify-center items-center;
&.left {
--at-apply: left-2 after:right--4px;
}
@@ -205,7 +234,7 @@ function toggleDockHide(hide: boolean) {
}
&.bottom {
--at-apply: top-unset bottom-0 flex-row;
--at-apply: top-unset bottom-0;
}
&.bottom.hide {
--at-apply: opacity-0 translate-y-100%;
@@ -218,6 +247,33 @@ function toggleDockHide(hide: boolean) {
&.bottom .divider {
--at-apply: w-4px h-auto my-3 mx-1;
}
.dock-content-inner {
--at-apply: duration-300 ease-in-out transform-gpu;
--at-apply: p-2 m-2 bg-$bew-content-2 dark:bg-$bew-elevated-1;
--at-apply: flex flex-col gap-2 shrink-0;
--at-apply: rounded-full border-$bew-border-color;
--at-apply: shadow-$bew-shadow-2;
backdrop-filter: var(--bew-filter-glass-1);
}
&.bottom .dock-content-inner {
--at-apply: flex-row;
}
.back-to-top-or-refresh-btn {
--at-apply: absolute md:bottom--45px bottom--35px;
--at-apply: md:w-45px w-35px md:h-45px h-35px;
--at-apply: grid place-items-center;
--at-apply: filter-$bew-filter-glass-1;
--at-apply: bg-$bew-elevated-1 hover:bg-$bew-content-1-hover dark-hover:bg-$bew-elevated-2;
--at-apply: rounded-full shadow-$bew-shadow-2;
backdrop-filter: var(--bew-filter-glass-1);
}
&.bottom .back-to-top-or-refresh-btn {
--at-apply: bottom-unset md:right--45px right--35px;
}
}
.dock-item {

View File

@@ -207,6 +207,9 @@ function handleToggleDockItem(dockItem: any) {
<SettingsItem :title="$t('settings.disable_light_dark_mode_switcher')">
<Radio v-model="settings.disableLightDarkModeSwitcherOnDock" />
</SettingsItem>
<SettingsItem :title="$t('settings.move_back_to_top_and_refresh_to_dock')">
<Radio v-model="settings.moveBackToTopOrRefreshButtonToDock" />
</SettingsItem>
</SettingsItemGroup>
</div>
</template>

View File

@@ -5,10 +5,11 @@ import type { AppPage } from '~/enums/appEnums'
export interface BewlyAppProvider {
activatedPage: Ref<AppPage>
scrollbarRef: Ref<any>
reachTop: Ref<boolean>
mainAppRef: Ref<HTMLElement>
handleReachBottom: Ref<(() => void) | undefined>
handlePageRefresh: Ref<(() => void) | undefined>
handleBackToTop: (targetScrollTop: number) => void
handleBackToTop: (targetScrollTop?: number) => void
}
export function useBewlyApp(): BewlyAppProvider {

View File

@@ -37,6 +37,7 @@ const handleReachBottom = ref<() => void>()
const handleThrottledPageRefresh = useThrottleFn(() => handlePageRefresh.value?.(), 500)
const handleThrottledReachBottom = useThrottleFn(() => handleReachBottom.value?.(), 500)
const topBarRef = ref()
const reachTop = ref<boolean>(false)
const isVideoPage = computed(() => {
if (/https?:\/\/(www.)?bilibili.com\/video\/.*/.test(location.href))
@@ -209,10 +210,14 @@ function handleOsScroll() {
const { viewport } = osInstance.elements()
const { scrollTop, scrollHeight, clientHeight } = viewport // get scroll offset
if (scrollTop === 0)
if (scrollTop === 0) {
showTopBarMask.value = false
else
reachTop.value = true
}
else {
showTopBarMask.value = true
reachTop.value = false
}
if (clientHeight + scrollTop >= scrollHeight - 150)
handleThrottledReachBottom()
@@ -282,6 +287,7 @@ provide<BewlyAppProvider>('BEWLY_APP', {
activatedPage,
mainAppRef,
scrollbarRef,
reachTop,
handleBackToTop,
handlePageRefresh,
handleReachBottom,
@@ -360,7 +366,8 @@ provide<BewlyAppProvider>('BEWLY_APP', {
>
<!-- control button group -->
<BackToTopAndRefreshButtons
v-if="activatedPage !== AppPage.Search" :show-refresh-button="!showTopBarMask"
v-if="activatedPage !== AppPage.Search && !settings.moveBackToTopOrRefreshButtonToDock"
:show-refresh-button="!showTopBarMask"
@refresh="handleThrottledPageRefresh"
@back-to-top="handleBackToTop"
/>

View File

@@ -23,6 +23,7 @@ export interface Settings {
autoHideDock: boolean
dockItemVisibilityList: { page: AppPage, visible: boolean }[]
disableLightDarkModeSwitcherOnDock: boolean
moveBackToTopOrRefreshButtonToDock: boolean
theme: 'light' | 'dark' | 'auto'
themeColor: string
@@ -71,6 +72,7 @@ export const settings = useStorageLocal('settings', ref<Settings>({
reduceFrostedGlassBlur: false,
dockItemVisibilityList: [],
disableLightDarkModeSwitcherOnDock: false,
moveBackToTopOrRefreshButtonToDock: false,
theme: 'auto',
themeColor: '#00a1d6',