mirror of
https://github.com/BewlyBewly/BewlyBewly.git
synced 2025-04-14 13:15:29 +00:00
feat(Dock): add config to move back-to-top or refresh button to dock
This commit is contained in:
@@ -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: 主题
|
||||
|
||||
@@ -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: 主題
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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: 色系
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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"
|
||||
/>
|
||||
|
||||
@@ -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',
|
||||
|
||||
Reference in New Issue
Block a user