mirror of
https://github.com/BewlyBewly/BewlyBewly.git
synced 2025-04-14 13:15:29 +00:00
fix(settings, top-bar): chromium transfrom (#1271)
Co-authored-by: Hakadao <a578457889743@gmail.com>
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { onClickOutside } from '@vueuse/core'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import { settings } from '~/logic'
|
||||
import { createTransformer } from '~/utils/transformer'
|
||||
|
||||
import type { MenuItem } from './types'
|
||||
import { MenuType } from './types'
|
||||
@@ -21,6 +23,17 @@ const settingsMenu = {
|
||||
}
|
||||
const activatedMenuItem = ref<MenuType>(MenuType.General)
|
||||
const title = ref<string>(t('settings.title'))
|
||||
const window = ref<HTMLDivElement>()
|
||||
createTransformer(window, {
|
||||
x: '50%',
|
||||
y: '50%',
|
||||
notrigger: true,
|
||||
centerTarget: {
|
||||
x: true,
|
||||
y: true,
|
||||
},
|
||||
})
|
||||
|
||||
const scrollbarRef = ref()
|
||||
|
||||
watch(
|
||||
@@ -104,6 +117,8 @@ function setCurrentTitle() {
|
||||
title.value = item.title
|
||||
})
|
||||
}
|
||||
|
||||
onClickOutside(window, handleClose)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -112,11 +127,12 @@ function setCurrentTitle() {
|
||||
class="fixed w-full h-full top-0 left-0"
|
||||
@click="handleClose"
|
||||
/>
|
||||
|
||||
<div
|
||||
id="settings-window" pos="fixed top-1/2 left-1/2" w="90%" h="90%"
|
||||
id="settings-window"
|
||||
ref="window"
|
||||
pos="fixed top-1/2 left-1/2" w="90%" h="90%"
|
||||
max-w-1000px max-h-900px transform="~ translate-x--1/2 translate-y--1/2 gpu"
|
||||
flex justify-between items-center
|
||||
flex="~ justify-between items-center"
|
||||
>
|
||||
<aside
|
||||
:class="{ group: !settings.touchScreenOptimization }"
|
||||
@@ -169,7 +185,7 @@ function setCurrentTitle() {
|
||||
--un-shadow: var(--bew-shadow-4), var(--bew-shadow-edge-glow-2);
|
||||
backdrop-filter: var(--bew-filter-glass-2);
|
||||
"
|
||||
relative overflow="x-hidde" w-full h-full bg="$bew-elevated-alt"
|
||||
relative overflow="x-hidden" w-full h-full bg="$bew-elevated-alt"
|
||||
shadow rounded="$bew-radius" border="1 $bew-border-color" transform-gpu
|
||||
>
|
||||
<header
|
||||
|
||||
@@ -10,6 +10,7 @@ import { settings } from '~/logic'
|
||||
import api from '~/utils/api'
|
||||
import { getUserID, isHomePage, isInIframe } from '~/utils/main'
|
||||
import emitter from '~/utils/mitt'
|
||||
import { createTransformer } from '~/utils/transformer'
|
||||
|
||||
import BewlyOrBiliPageSwitcher from './components/BewlyOrBiliPageSwitcher.vue'
|
||||
import ChannelsPop from './components/ChannelsPop.vue'
|
||||
@@ -50,8 +51,6 @@ const isLogin = ref<boolean>(true)
|
||||
const logo = ref<HTMLElement>() as Ref<HTMLElement>
|
||||
const avatarImg = ref<HTMLImageElement>() as Ref<HTMLImageElement>
|
||||
const avatarShadow = ref<HTMLImageElement>() as Ref<HTMLImageElement>
|
||||
const favoritesPopRef = ref<any>()
|
||||
const momentsPopRef = ref()
|
||||
|
||||
const scrollTop = ref<number>(0)
|
||||
const oldScrollTop = ref<number>(0)
|
||||
@@ -198,7 +197,7 @@ const upload = setupTopBarItemHoverEvent('upload')
|
||||
// More
|
||||
const more = setupTopBarItemHoverEvent('more')
|
||||
|
||||
const topBarItemElements = {
|
||||
const topBarItemElements: Record<keyof typeof popupVisible, Ref<HTMLElement | undefined>> = {
|
||||
channels,
|
||||
userPanel: avatar,
|
||||
notifications,
|
||||
@@ -207,6 +206,29 @@ const topBarItemElements = {
|
||||
history,
|
||||
watchLater,
|
||||
upload,
|
||||
more,
|
||||
}
|
||||
|
||||
const channelsTransformer = setupTopBarItemTransformer('channels')
|
||||
const avatarTransformer = setupTopBarItemTransformer('userPanel')
|
||||
const notificationsTransformer = setupTopBarItemTransformer('notifications')
|
||||
const momentsTransformer = setupTopBarItemTransformer('moments')
|
||||
const favoritesTransformer = setupTopBarItemTransformer('favorites')
|
||||
const historyTransformer = setupTopBarItemTransformer('history')
|
||||
const watchLaterTransformer = setupTopBarItemTransformer('watchLater')
|
||||
const uploadTransformer = setupTopBarItemTransformer('upload')
|
||||
const moreTransformer = setupTopBarItemTransformer('more')
|
||||
|
||||
function setupTopBarItemTransformer(key: keyof typeof popupVisible) {
|
||||
const transformer = createTransformer(topBarItemElements[key], {
|
||||
x: '0px',
|
||||
y: '60px',
|
||||
centerTarget: {
|
||||
x: true,
|
||||
},
|
||||
})
|
||||
|
||||
return transformer
|
||||
}
|
||||
|
||||
function setupTopBarItemHoverEvent(key: keyof typeof popupVisible) {
|
||||
@@ -280,8 +302,9 @@ watch(() => popupVisible.favorites, (newVal, oldVal) => {
|
||||
return
|
||||
if (newVal) {
|
||||
nextTick(() => {
|
||||
if (favoritesPopRef.value)
|
||||
favoritesPopRef.value.refreshFavoriteResources()
|
||||
if (favoritesTransformer.value)
|
||||
// @ts-expect-error allow
|
||||
favoritesTransformer.value.refreshFavoriteResources()
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -519,7 +542,8 @@ defineExpose({
|
||||
|
||||
<Transition name="slide-in">
|
||||
<ChannelsPop
|
||||
v-show="popupVisible.channels"
|
||||
v-if="popupVisible.channels"
|
||||
ref="channelsTransformer"
|
||||
class="bew-popover"
|
||||
pos="!left-0 !top-70px"
|
||||
transform="!translate-x-0"
|
||||
@@ -618,7 +642,7 @@ defineExpose({
|
||||
<Transition name="slide-in">
|
||||
<MomentsPop
|
||||
v-show="popupVisible.moments"
|
||||
ref="momentsPopRef"
|
||||
ref="momentsTransformer"
|
||||
class="bew-popover"
|
||||
@click.stop="() => {}"
|
||||
/>
|
||||
@@ -645,7 +669,7 @@ defineExpose({
|
||||
<KeepAlive>
|
||||
<FavoritesPop
|
||||
v-if="popupVisible.favorites"
|
||||
ref="favoritesPopRef"
|
||||
ref="favoritesTransformer"
|
||||
class="bew-popover"
|
||||
@click.stop="() => {}"
|
||||
/>
|
||||
@@ -672,6 +696,7 @@ defineExpose({
|
||||
<Transition name="slide-in">
|
||||
<HistoryPop
|
||||
v-if="popupVisible.history"
|
||||
ref="historyTransformer"
|
||||
class="bew-popover"
|
||||
@click.stop="() => {}"
|
||||
/>
|
||||
@@ -697,6 +722,7 @@ defineExpose({
|
||||
<Transition name="slide-in">
|
||||
<WatchLaterPop
|
||||
v-if="popupVisible.watchLater"
|
||||
ref="watchLaterTransformer"
|
||||
class="bew-popover"
|
||||
@click.stop="() => {}"
|
||||
/>
|
||||
@@ -733,6 +759,7 @@ defineExpose({
|
||||
<Transition name="slide-in">
|
||||
<MorePop
|
||||
v-show="popupVisible.more"
|
||||
ref="moreTransformer"
|
||||
class="bew-popover"
|
||||
@click.stop="() => {}"
|
||||
/>
|
||||
@@ -768,6 +795,7 @@ defineExpose({
|
||||
<Transition name="slide-in">
|
||||
<UploadPop
|
||||
v-if="popupVisible.upload"
|
||||
ref="uploadTransformer"
|
||||
class="bew-popover"
|
||||
@click.stop="() => {}"
|
||||
/>
|
||||
@@ -805,6 +833,7 @@ defineExpose({
|
||||
<Transition name="slide-in">
|
||||
<NotificationsPop
|
||||
v-if="popupVisible.notifications"
|
||||
ref="notificationsTransformer"
|
||||
class="bew-popover"
|
||||
@click.stop="() => {}"
|
||||
/>
|
||||
@@ -858,9 +887,10 @@ defineExpose({
|
||||
<Transition name="slide-in">
|
||||
<UserPanelPop
|
||||
v-if="popupVisible.userPanel"
|
||||
class="bew-popover"
|
||||
ref="avatarTransformer"
|
||||
:user-info="userInfo"
|
||||
after:h="!0"
|
||||
class="bew-popover"
|
||||
pos="!left-auto !right-0" transform="!translate-x-0"
|
||||
@click.stop="() => {}"
|
||||
/>
|
||||
@@ -891,7 +921,7 @@ defineExpose({
|
||||
|
||||
.slide-in-leave-to,
|
||||
.slide-in-enter-from {
|
||||
--uno: "transform important:translate-y-4 opacity-0";
|
||||
--uno: "transform !top-full opacity-0";
|
||||
}
|
||||
|
||||
.slide-out-enter-active,
|
||||
|
||||
150
src/utils/transformer.ts
Normal file
150
src/utils/transformer.ts
Normal file
@@ -0,0 +1,150 @@
|
||||
import type { MaybeElement } from '@vueuse/core'
|
||||
import { unrefElement, useElementVisibility } from '@vueuse/core'
|
||||
import type { CSSProperties } from 'vue'
|
||||
|
||||
interface TransformerCenter {
|
||||
x?: boolean
|
||||
y?: boolean
|
||||
}
|
||||
|
||||
export interface Transformer {
|
||||
x: number | string
|
||||
y: number | string
|
||||
centerTarget?: TransformerCenter
|
||||
notrigger?: boolean
|
||||
}
|
||||
|
||||
function checkChromium(): boolean {
|
||||
return navigator.userAgent.includes('Chrome')
|
||||
}
|
||||
|
||||
/**
|
||||
* Covert transform to top and left style, if no chromium, use transform
|
||||
* @param trigger
|
||||
* @param transformer
|
||||
*/
|
||||
export function createTransformer(trigger: Ref<MaybeElement>, transformer: Transformer) {
|
||||
const target = ref<MaybeElement>()
|
||||
const isChromium = checkChromium()
|
||||
const style = ref<CSSProperties>({})
|
||||
|
||||
watch(trigger, () => {
|
||||
if (transformer.notrigger) {
|
||||
target.value = unrefElement(trigger)
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
function update() {
|
||||
let x = '0px'
|
||||
let y = '0px'
|
||||
|
||||
if (typeof transformer.x === 'number') {
|
||||
x = `${transformer.x}px`
|
||||
}
|
||||
else {
|
||||
x = transformer.x
|
||||
}
|
||||
|
||||
if (typeof transformer.y === 'number') {
|
||||
y = `${transformer.y}px`
|
||||
}
|
||||
else {
|
||||
y = transformer.y
|
||||
}
|
||||
|
||||
if (target.value && transformer.centerTarget && isChromium) {
|
||||
const el = unrefElement(target.value)
|
||||
const targetRect = el!.getBoundingClientRect()
|
||||
|
||||
if (transformer.centerTarget.x) {
|
||||
x = `calc(${transformer.x} - ${targetRect.width / 2}px)`
|
||||
}
|
||||
|
||||
if (transformer.centerTarget.y) {
|
||||
y = `calc(${transformer.y} - ${targetRect.height / 2}px)`
|
||||
}
|
||||
}
|
||||
|
||||
if (isChromium) {
|
||||
style.value = {
|
||||
// transition: 'none !important',
|
||||
transform: 'none !important',
|
||||
top: y,
|
||||
left: x,
|
||||
}
|
||||
}
|
||||
else {
|
||||
// nothing, use inherit transform
|
||||
// style.value = {
|
||||
// transform: `translate(${x}, ${y})`,
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
function generateStyle(originStyle: string | undefined | null): string {
|
||||
const s = (originStyle || '')
|
||||
.split(';')
|
||||
.map((item) => {
|
||||
const [key, value] = item.split(':').map(item => item.trim())
|
||||
|
||||
if (!key || !value) {
|
||||
return {}
|
||||
}
|
||||
|
||||
return {
|
||||
[key]: value,
|
||||
}
|
||||
})
|
||||
.reduce((acc, item) => {
|
||||
return {
|
||||
...acc,
|
||||
...item,
|
||||
}
|
||||
}, {})
|
||||
|
||||
for (const key in style.value) {
|
||||
// @ts-expect-error ignore
|
||||
s[key] = style.value[key]
|
||||
}
|
||||
|
||||
return Object.keys(s).map(key => `${key}:${s[key]}`).join(';')
|
||||
}
|
||||
|
||||
if (isChromium) {
|
||||
// v-show
|
||||
const targetVisibility = useElementVisibility(() => unrefElement(target))
|
||||
watch(targetVisibility, (visible) => {
|
||||
if (visible) {
|
||||
const targetElement = unrefElement(target)
|
||||
if (targetElement) {
|
||||
update()
|
||||
const style = targetElement.getAttribute('style')
|
||||
targetElement.setAttribute('style', generateStyle(style))
|
||||
}
|
||||
}
|
||||
}, { flush: 'pre' })
|
||||
|
||||
// v-show
|
||||
// useEventListener(() => unrefElement(target), 'transitionstart', () => {
|
||||
// update()
|
||||
// const style = unrefElement(target)?.getAttribute('style')
|
||||
// unrefElement(target)?.setAttribute('style', generateStyle(style))
|
||||
// })
|
||||
|
||||
// useEventListener(() => unrefElement(target), 'transitionend', () => {
|
||||
// const style = unrefElement(target)?.getAttribute('style')
|
||||
// unrefElement(target)?.setAttribute('style', generateStyle(style))
|
||||
// })
|
||||
|
||||
// v-if
|
||||
watch(() => unrefElement(target), (targetElement) => {
|
||||
if (targetElement) {
|
||||
update()
|
||||
const style = targetElement.getAttribute('style')
|
||||
targetElement.setAttribute('style', generateStyle(style))
|
||||
}
|
||||
}, { flush: 'pre' })
|
||||
}
|
||||
|
||||
return target
|
||||
}
|
||||
Reference in New Issue
Block a user