mirror of
https://github.com/BewlyBewly/BewlyBewly.git
synced 2025-04-14 13:15:29 +00:00
feat(iframe-page): improve loading experience and support for new watch later URL
- Add loading state and transition for iframe content - Implement delayed loading animation to prevent unnecessary flashes - Update supported URL patterns for watch later pages - Enhance iframe page rendering with smooth transitions - Add support for new Bilibili watch later list URL format
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { useDark } from '~/composables/useDark'
|
||||
import { delay } from '~/utils/main'
|
||||
|
||||
const props = defineProps<{
|
||||
url: string
|
||||
@@ -8,12 +9,32 @@ const { isDark } = useDark()
|
||||
const headerShow = ref(false)
|
||||
const iframeRef = ref<HTMLIFrameElement | null>(null)
|
||||
const currentUrl = ref<string>(props.url)
|
||||
const showIframe = ref<boolean>(false)
|
||||
const showLoading = ref<boolean>(false)
|
||||
|
||||
watch(() => isDark.value, (newValue) => {
|
||||
iframeRef.value?.contentDocument?.documentElement.classList.toggle('dark', newValue)
|
||||
iframeRef.value?.contentDocument?.body?.classList.toggle('dark', newValue)
|
||||
})
|
||||
|
||||
watch(() => props.url, () => {
|
||||
showIframe.value = false
|
||||
})
|
||||
|
||||
// Only show loading animation after 2 seconds to prevent annoying flash when content loads quickly
|
||||
const showLoadingTimeout = ref()
|
||||
watch(() => showIframe.value, async (newValue) => {
|
||||
clearTimeout(showLoadingTimeout.value)
|
||||
if (!newValue) {
|
||||
showLoadingTimeout.value = setTimeout(() => {
|
||||
showLoading.value = true
|
||||
}, 2000)
|
||||
}
|
||||
else {
|
||||
showLoading.value = false
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
iframeRef.value?.focus()
|
||||
@@ -67,18 +88,25 @@ defineExpose({
|
||||
<div
|
||||
pos="relative top-0 left-0" of-hidden w-full h-full
|
||||
>
|
||||
<!-- Iframe -->
|
||||
<iframe
|
||||
ref="iframeRef"
|
||||
:src="props.url"
|
||||
:style="{
|
||||
bottom: headerShow ? `var(--bew-top-bar-height)` : '0',
|
||||
}"
|
||||
frameborder="0"
|
||||
pointer-events-auto
|
||||
pos="absolute left-0"
|
||||
w-inherit h-inherit
|
||||
/>
|
||||
<Transition name="fade">
|
||||
<Loading v-if="showLoading" w-full h-full pos="absolute top-0 left-0" />
|
||||
</Transition>
|
||||
<Transition name="fade">
|
||||
<!-- Iframe -->
|
||||
<iframe
|
||||
v-show="showIframe"
|
||||
ref="iframeRef"
|
||||
:src="props.url"
|
||||
:style="{
|
||||
bottom: headerShow ? `var(--bew-top-bar-height)` : '0',
|
||||
}"
|
||||
frameborder="0"
|
||||
pointer-events-auto
|
||||
pos="absolute left-0"
|
||||
w-inherit h-inherit
|
||||
@load="showIframe = true"
|
||||
/>
|
||||
</Transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ function isSupportedPages(): boolean {
|
||||
|| /https?:\/\/(?:www\.)?bilibili\.com\/account\/history.*/.test(currentUrl)
|
||||
// watcher later page
|
||||
|| /https?:\/\/(?:www\.)?bilibili\.com\/watchlater\/#\/list.*/.test(currentUrl)
|
||||
|| /https?:\/\/(?:www\.)?bilibili\.com\/watchlater\/list.*/.test(currentUrl)
|
||||
// user space page
|
||||
|| /https?:\/\/space\.bilibili\.com\.*/.test(currentUrl)
|
||||
// notifications page
|
||||
@@ -97,6 +98,7 @@ export function isSupportedIframePages(): boolean {
|
||||
|| /https?:\/\/space\.bilibili\.com\/\d+\/favlist.*/.test(currentUrl)
|
||||
|| /https?:\/\/www\.bilibili\.com\/history.*/.test(currentUrl)
|
||||
|| /https?:\/\/www\.bilibili\.com\/watchlater\/#\/list.*/.test(currentUrl)
|
||||
|| /https?:\/\/www\.bilibili\.com\/watchlater\/list.*/.test(currentUrl)
|
||||
// moments page
|
||||
// https://github.com/BewlyBewly/BewlyBewly/issues/1246
|
||||
// https://github.com/BewlyBewly/BewlyBewly/issues/1256
|
||||
|
||||
@@ -387,28 +387,33 @@ provide<BewlyAppProvider>('BEWLY_APP', {
|
||||
height: showBewlyPage || iframePageURL ? '100dvh' : '0',
|
||||
}"
|
||||
>
|
||||
<template v-if="showBewlyPage">
|
||||
<OverlayScrollbarsComponent ref="scrollbarRef" element="div" h-inherit defer @os-scroll="handleOsScroll">
|
||||
<main m-auto max-w="$bew-page-max-width">
|
||||
<div
|
||||
p="t-[calc(var(--bew-top-bar-height)+10px)]" m-auto
|
||||
w="lg:[calc(100%-200px)] [calc(100%-150px)]"
|
||||
>
|
||||
<!-- control button group -->
|
||||
<BackToTopOrRefreshButton
|
||||
v-if="activatedPage !== AppPage.Search && !settings.moveBackToTopOrRefreshButtonToDock"
|
||||
@refresh="handleThrottledPageRefresh"
|
||||
@back-to-top="handleThrottledBackToTop"
|
||||
/>
|
||||
<Transition name="fade">
|
||||
<template v-if="showBewlyPage">
|
||||
<OverlayScrollbarsComponent ref="scrollbarRef" element="div" h-inherit defer @os-scroll="handleOsScroll">
|
||||
<main m-auto max-w="$bew-page-max-width">
|
||||
<div
|
||||
p="t-[calc(var(--bew-top-bar-height)+10px)]" m-auto
|
||||
w="lg:[calc(100%-200px)] [calc(100%-150px)]"
|
||||
>
|
||||
<!-- control button group -->
|
||||
<BackToTopOrRefreshButton
|
||||
v-if="activatedPage !== AppPage.Search && !settings.moveBackToTopOrRefreshButtonToDock"
|
||||
@refresh="handleThrottledPageRefresh"
|
||||
@back-to-top="handleThrottledBackToTop"
|
||||
/>
|
||||
|
||||
<Transition name="page-fade">
|
||||
<Component :is="pages[activatedPage]" />
|
||||
</Transition>
|
||||
</div>
|
||||
</main>
|
||||
</OverlayScrollbarsComponent>
|
||||
</template>
|
||||
<IframePage v-else-if="iframePageURL && !isInIframe()" ref="iframePageRef" :url="iframePageURL" />
|
||||
<Transition name="page-fade">
|
||||
<Component :is="pages[activatedPage]" />
|
||||
</Transition>
|
||||
</div>
|
||||
</main>
|
||||
</OverlayScrollbarsComponent>
|
||||
</template>
|
||||
</Transition>
|
||||
|
||||
<Transition v-if="!showBewlyPage && iframePageURL && !isInIframe()" name="fade">
|
||||
<IframePage ref="iframePageRef" :url="iframePageURL" />
|
||||
</Transition>
|
||||
</div>
|
||||
|
||||
<IframeDrawer
|
||||
|
||||
@@ -11,7 +11,7 @@ export interface DockItem {
|
||||
page: AppPage
|
||||
openInNewTab: boolean
|
||||
useOriginalBiliPage: boolean
|
||||
url: string
|
||||
url: string | string[]
|
||||
hasBewlyPage: boolean // Whether BewlyBewly has a page for this item
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ export const useMainStore = defineStore('main', () => {
|
||||
page: AppPage.WatchLater,
|
||||
openInNewTab: false,
|
||||
useOriginalBiliPage: false,
|
||||
url: `https://www.bilibili.com/watchlater/#/list`,
|
||||
url: `https://www.bilibili.com/watchlater/list`,
|
||||
hasBewlyPage: true,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -173,7 +173,7 @@ export function isVideoOrBangumiPage(url: string = location.href): boolean {
|
||||
// anime playback & movie page
|
||||
|| /https?:\/\/(?:www\.)?bilibili\.com\/bangumi\/play\/.*/.test(url)
|
||||
// watch later playlist
|
||||
|| /https?:\/\/(?:www\.)?bilibili\.com\/list\/watchlater.*/.test(url)
|
||||
|| /https?:\/\/(?:www\.)?bilibili\.com\/list\/watchlater\?bvid.*/.test(url)
|
||||
|| /https?:\/\/(?:www\.)?bilibili\.com\/watchlater\/list.*/.test(url)
|
||||
// favorite playlist
|
||||
|| /https?:\/\/(?:www\.)?bilibili\.com\/list\/ml.*/.test(url)) {
|
||||
@@ -316,5 +316,12 @@ export function queryDomUntilFound(selector: string, timeout = 500, abort?: Abor
|
||||
* @returns true if the current page is in an iframe
|
||||
*/
|
||||
export function isInIframe(): boolean {
|
||||
return window.self !== window.top
|
||||
try {
|
||||
return window.self !== window.top
|
||||
}
|
||||
catch (e) {
|
||||
// If we can't access window.top due to security restrictions,
|
||||
// we're definitely in an iframe
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user