Merge branch 'dev' into refactor-message-listeners

This commit is contained in:
Hakadao
2024-04-11 16:57:44 +08:00
parent 38b9dfe227
commit 1a3bafb284
43 changed files with 784 additions and 145 deletions

View File

@@ -3,6 +3,7 @@ interface Props {
type?: | 'default'
| 'primary'
| 'secondary'
| 'tertiary'
| 'info'
| 'success'
| 'warning'
@@ -92,6 +93,12 @@ function handleClick(evt: MouseEvent) {
--b-button-text-color: var(--bew-text-1);
}
&--type-tertiary {
--b-button-color: transparent;
--b-button-color-hover: var(--bew-fill-2);
--b-button-text-color: var(--bew-text-1);
}
&--type-error {
--b-button-color: var(--bew-error-color);
--b-button-color-hover: var(--bew-error-color)
@@ -113,7 +120,7 @@ function handleClick(evt: MouseEvent) {
}
&--custom-color {
--at-apply: hover:opacity-80;
--at-apply: hover:opacity-70;
}
&--strong {

172
src/components/Dialog.vue Normal file
View File

@@ -0,0 +1,172 @@
<script setup lang="ts">
import { Icon } from '@iconify/vue'
import { onKeyStroke } from '@vueuse/core'
const props = withDefaults(defineProps<{
title: string
desc?: string
center?: boolean
appendToBewlyBody?: boolean
width?: string | number
height?: string | number
centerFooter?: boolean
loading?: boolean
preventCloseWhenLoading?: boolean
}>(), {
preventCloseWhenLoading: true,
})
const emit = defineEmits(['close', 'confirm'])
onKeyStroke('Enter', (e: KeyboardEvent) => {
e.preventDefault()
if (!props.loading)
handleConfirm()
})
onKeyStroke('Escape', (e: KeyboardEvent) => {
e.preventDefault()
if (props.loading && props.preventCloseWhenLoading)
return
handleClose()
})
const showShortcut = ref<boolean>(false)
const { mainAppRef } = useBewlyApp()
const showDialog = ref<boolean>(false)
const dialogWidth = computed(() => {
return typeof props.width === 'number' ? `${props.width}px` : props.width || '400px'
})
const dialogHeight = computed(() => {
return typeof props.height === 'number' ? `${props.height}px` : props.height || 'auto'
})
onKeyStroke('Alt', (e: KeyboardEvent) => {
e.preventDefault()
showShortcut.value = true
}, { eventName: 'keydown' })
onKeyStroke('Alt', (e: KeyboardEvent) => {
e.preventDefault()
showShortcut.value = false
}, { eventName: 'keyup' })
onMounted(() => {
showDialog.value = true
})
onBeforeUnmount(() => {
handleClose()
})
function handleClose() {
if (props.loading && props.preventCloseWhenLoading)
return
showDialog.value = false
nextTick(() => {
emit('close')
})
}
function handleConfirm() {
emit('confirm')
if (!props.loading)
handleClose()
}
</script>
<template>
<Teleport :to="mainAppRef" :disabled="!appendToBewlyBody">
<Transition name="modal">
<div
v-if="showDialog"
class="dialog"
pos="fixed top-0 left-0" w-full h-full z-100
>
<div
bg="black opacity-40 dark:opacity-40"
pos="absolute top-0 left-0" w-full h-full z-0
@click="handleClose"
/>
<div
style="
box-shadow: var(--bew-shadow-3) var(--bew-shadow-edge-glow-2);
backdrop-filter: var(--bew-filter-glass-2);
"
:style="{ width: dialogWidth, height: dialogHeight }"
pos="absolute top-1/2 left-1/2" bg="$bew-elevated-1" rounded="$bew-radius"
transform="translate--1/2" z-2 overflow="x-hidden y-overlay"
antialiased
>
<!-- loading masking -->
<Transition name="fade">
<div
v-if="loading"
pos="absolute top-0 left-0" w-full h-full bg="white dark:black opacity-60 dark:opacity-60" flex="~ justify-center items-center"
z-2
>
<Icon icon="svg-spinners:ring-resize" text="4xl" />
</div>
</Transition>
<header
style="
text-shadow: 0 0 15px var(--bew-elevated-solid-1), 0 0 20px var(--bew-elevated-solid-1)
"
pos="sticky top-0 left-0" w-full h-70px px-8 flex
items-center justify-between
rounded="t-$bew-radius" z-1
>
<div
:style="{ textAlign: center ? 'center' : 'left' }"
w-full
>
<p text-xl fw-bold>
{{ title }}
</p>
<p text="sm $bew-text-2">
<slot name="desc">
{{ desc }}
</slot>
</p>
</div>
<div
style="backdrop-filter: var(--bew-filter-glass-1)"
text-2xl leading-0 bg="$bew-fill-1 hover:$bew-theme-color-30" w="32px" h="32px"
ml-8 p="1" rounded-8 cursor="pointer"
hover:ring="2 $bew-theme-color" hover:text="$bew-theme-color" duration-300
@click="handleClose"
>
<ic-baseline-clear />
</div>
</header>
<main p="x-8 y-2" relative>
<!-- <div h-80px mt--8 /> -->
<slot />
</main>
<footer
:style="{ justifyContent: centerFooter || center ? 'center' : 'flex-end' }"
flex="~ gap-2" p="x-8 t-6 b-6"
>
<Button type="tertiary" @click="handleClose">
<div>
{{ $t('common.cancel') }}
<span v-show="showShortcut" text="xs $bew-text-2">(Esc)</span>
</div>
</Button>
<Button type="primary" @click="handleConfirm">
<div>
{{ $t('common.confirm') }}
<span v-show="showShortcut" text="xs">(Enter)</span>
</div>
</Button>
</footer>
</div>
</div>
</Transition>
</Teleport>
</template>
<style lang="scss" scoped>
</style>

View File

@@ -16,6 +16,7 @@ const settingsMenu = {
[MenuType.SearchPage]: defineAsyncComponent(() => import('./components/SearchPage.vue')),
[MenuType.Home]: defineAsyncComponent(() => import('./components/Home.vue')),
[MenuType.Compatibility]: defineAsyncComponent(() => import('./components/Compatibility.vue')),
// [MenuType.BilibiliSettings]: defineAsyncComponent(() => import('./components/BilibiliSettings.vue')),
[MenuType.About]: defineAsyncComponent(() => import('./components/About.vue')),
}
const activatedMenuItem = ref<MenuType>(MenuType.General)
@@ -65,6 +66,12 @@ const settingsMenuItems = computed((): MenuItem[] => {
iconActivated: 'mingcute:polygon-fill',
title: t('settings.menu_compatibility'),
},
// {
// value: MenuType.BilibiliSettings,
// icon: 'ant-design:bilibili-outlined',
// iconActivated: 'ant-design:bilibili-outlined',
// title: 'Bilibili',
// },
{
value: MenuType.About,
icon: 'mingcute:information-line',

View File

@@ -66,6 +66,10 @@ const themeOptions = computed<Array<{ value: string, label: string }>>(() => {
]
})
watch(() => settings.value.wallpaper, (newValue) => {
changeWallpaper(newValue)
})
function changeThemeColor(color: string) {
settings.value.themeColor = color
}

View File

@@ -0,0 +1,20 @@
<template>
<div flex="~ justify-between gap-4">
<aside>
<ul flex="~ col gap-1" ml--4>
<li p="x-4 y-2" bg="hover:$bew-fill-2" rounded="$bew-radius">
home page
</li>
<li p="x-4 y-2" bg="hover:$bew-fill-2" rounded="$bew-radius">
video page
</li>
<li p="x-4 y-2" bg="hover:$bew-fill-2" rounded="$bew-radius">
moments page
</li>
</ul>
</aside>
<main flex-1>
<span text="8xl">WIP...</span>
</main>
</div>
</template>

View File

@@ -4,6 +4,7 @@ export enum MenuType {
SearchPage = 'SearchPage',
Home = 'Home',
Compatibility = 'Compatibility',
BilibiliSettings = 'BilibiliSettings',
About = 'About',
}

View File

@@ -69,6 +69,47 @@ const favoritesPopRef = ref<any>()
const scrollTop = ref<number>(0)
const oldScrollTop = ref<number>(0)
// Avatar
const avatar = useDelayedHover({
enter: () => openUserPanel(),
leave: () => closeUserPanel(),
})
// Notifications
const notifications = useDelayedHover({
enter: () => showNotificationsPop.value = true,
leave: () => showNotificationsPop.value = false,
})
// Moments
const moments = useDelayedHover({
enter: () => showMomentsPop.value = true,
leave: () => showMomentsPop.value = false,
})
// Favorites
const favorites = useDelayedHover({
enter: () => showFavoritesPop.value = true,
leave: () => showFavoritesPop.value = false,
})
// Upload
const upload = useDelayedHover({
enter: () => showUploadPop.value = true,
leave: () => showUploadPop.value = false,
})
// History
const history = useDelayedHover({
enter: () => showHistoryPop.value = true,
leave: () => showHistoryPop.value = false,
})
// Watch Later
const watchLater = useDelayedHover({
enter: () => showWatchLaterPop.value = true,
leave: () => showWatchLaterPop.value = false,
})
// More
const more = useDelayedHover({
enter: () => showMorePop.value = true,
leave: () => showMorePop.value = false,
})
watch(() => settings.value.autoHideTopBar, (newVal) => {
if (!newVal)
toggleTopBarVisible(true)
@@ -379,9 +420,8 @@ defineExpose({
<template v-if="isLogin">
<!-- Avatar -->
<div
ref="avatar"
class="avatar right-side-item"
@mouseenter="openUserPanel"
@mouseleave="closeUserPanel"
>
<a
ref="avatarImg"
@@ -447,10 +487,9 @@ defineExpose({
<div display="lg:flex none" gap-1>
<!-- Notifications -->
<div
ref="notifications"
class="right-side-item"
:class="{ active: showNotificationsPop }"
@mouseenter="showNotificationsPop = true"
@mouseleave="showNotificationsPop = false"
>
<template v-if="unReadMessageCount > 0">
<div
@@ -482,10 +521,9 @@ defineExpose({
<!-- Moments -->
<div
ref="moments"
class="right-side-item"
:class="{ active: showMomentsPop }"
@mouseenter="showMomentsPop = true"
@mouseleave="showMomentsPop = false"
>
<template v-if="newMomentsCount > 0">
<div
@@ -516,10 +554,9 @@ defineExpose({
<!-- Favorites -->
<div
ref="favorites"
class="right-side-item"
:class="{ active: showFavoritesPop }"
@mouseenter="showFavoritesPop = true"
@mouseleave="showFavoritesPop = false"
>
<a
:href="`https://space.bilibili.com/${mid}/favlist`"
@@ -542,10 +579,9 @@ defineExpose({
<!-- History -->
<div
ref="history"
class="right-side-item"
:class="{ active: showHistoryPop }"
@mouseenter="showHistoryPop = true"
@mouseleave="showHistoryPop = false"
>
<a
href="https://www.bilibili.com/account/history"
@@ -562,10 +598,9 @@ defineExpose({
<!-- Watch later -->
<div
ref="watchLater"
class="right-side-item"
:class="{ active: showWatchLaterPop }"
@mouseenter="showWatchLaterPop = true"
@mouseleave="showWatchLaterPop = false"
>
<a
href="https://www.bilibili.com/watchlater/#/list"
@@ -594,11 +629,10 @@ defineExpose({
<!-- More -->
<div
ref="more"
class="right-side-item"
:class="{ active: showMorePop }"
display="lg:!none flex"
@mouseenter="showMorePop = true"
@mouseleave="showMorePop = false"
>
<a title="More">
<mingcute:menu-line />
@@ -611,9 +645,8 @@ defineExpose({
<!-- Upload -->
<div
ref="upload"
class="upload right-side-item"
@mouseenter="showUploadPop = true"
@mouseleave="showUploadPop = false"
>
<a
href="https://member.bilibili.com/platform/upload/video/frame"

View File

@@ -17,12 +17,16 @@ const isLoading = ref<boolean>(false)
const noMoreContent = ref<boolean>(false)
const favoriteVideosWrap = ref<HTMLElement>() as Ref<HTMLElement>
const favoritesPageUrl = computed(() => {
const viewAllUrl = computed((): string => {
return `//space.bilibili.com/${getUserID()}/favlist?fid=${
activatedMediaId.value
}`
})
const playAllUrl = computed((): string => {
return `https://www.bilibili.com/list/ml${activatedMediaId.value}`
})
watch(activatedMediaId, (newVal: number, oldVal: number) => {
if (newVal === oldVal)
return
@@ -148,12 +152,20 @@ defineExpose({
{{ activatedFavoriteTitle }}
</h3>
<a
:href="favoritesPageUrl" :target="isHomePage() ? '_blank' : '_self'" rel="noopener noreferrer"
flex="~" items="center"
>
<span text="sm">{{ $t('common.view_all') }}</span>
</a>
<div flex="~ gap-4">
<a
:href="playAllUrl" :target="isHomePage() ? '_blank' : '_self'" rel="noopener noreferrer"
flex="~" items="center"
>
<span text="sm">{{ $t('common.play_all') }}</span>
</a>
<a
:href="viewAllUrl" :target="isHomePage() ? '_blank' : '_self'" rel="noopener noreferrer"
flex="~" items="center"
>
<span text="sm">{{ $t('common.view_all') }}</span>
</a>
</div>
</header>
<main flex="~" overflow-hidden rounded="$bew-radius">

View File

@@ -380,8 +380,9 @@ function toggleWatchLater(aid: number) {
<div flex="~" justify="between" w="full">
<div>
<span v-if="selectedTab !== 1">{{ `${moment.name} ${t('topbar.moments_dropdown.uploaded')}` }}</span>
<span v-else>{{ `${moment.name} ${t('topbar.moments_dropdown.now_streaming')}` }}</span>
<!-- <span v-if="selectedTab !== 1">{{ `${moment.name} ${t('topbar.moments_dropdown.uploaded')}` }}</span> -->
<!-- <span v-else>{{ `${moment.name} ${t('topbar.moments_dropdown.now_streaming')}` }}</span> -->
<span font-bold>{{ moment.name }}</span>
<div overflow-hidden text-ellipsis break-anywhere>
{{ moment.title }}
</div>

View File

@@ -9,6 +9,7 @@ const list = [
{ name: t('topbar.moments'), url: '//t.bilibili.com/' },
{ name: t('topbar.favorites'), url: `//space.bilibili.com/${getUserID ?? ''}/favlist` },
{ name: t('topbar.history'), url: '//www.bilibili.com/account/history' },
{ name: t('topbar.watch_later'), url: '//www.bilibili.com/watchlater/#/list' },
{ name: t('topbar.creative_center'), url: '//member.bilibili.com/platform/home' },
]
</script>

View File

@@ -7,6 +7,13 @@ import { isHomePage, removeHttpFromUrl } from '~/utils/main'
const watchLaterList = reactive<VideoItem[]>([])
const isLoading = ref<boolean>()
const viewAllUrl = computed((): string => {
return 'https://www.bilibili.com/watchlater/#/list'
})
const playAllUrl = computed((): string => {
return 'https://www.bilibili.com/list/watchlater'
})
onMounted(() => {
getAllWatchLaterList()
})
@@ -42,11 +49,12 @@ function getAllWatchLaterList() {
<template>
<div
bg="$bew-elevated-solid-1"
w="380px"
shadow="$bew-shadow-2"
bg="$bew-elevated-solid-1"
rounded="$bew-radius"
pos="relative"
style="box-shadow: var(--bew-shadow-2)"
of="hidden"
>
<!-- top bar -->
<header
@@ -65,12 +73,21 @@ function getAllWatchLaterList() {
{{ $t('topbar.watch_later') }}
</div>
</div>
<a
href="https://www.bilibili.com/watchlater/#/list" :target="isHomePage() ? '_blank' : '_self'" rel="noopener noreferrer"
flex="~ items-center"
>
<span text="sm">{{ $t('common.view_all') }}</span>
</a>
<div flex="~ gap-4">
<a
:href="playAllUrl" :target="isHomePage() ? '_blank' : '_self'" rel="noopener noreferrer"
flex="~" items="center"
>
<span text="sm">{{ $t('common.play_all') }}</span>
</a>
<a
:href="viewAllUrl" :target="isHomePage() ? '_blank' : '_self'" rel="noopener noreferrer"
flex="~" items="center"
>
<span text="sm">{{ $t('common.view_all') }}</span>
</a>
</div>
</header>
<!-- watchLater wrapper -->

View File

@@ -1,4 +1,5 @@
<script lang="ts" setup>
import { Icon } from '@iconify/vue'
import { getCSRF, removeHttpFromUrl } from '~/utils/main'
import { calcCurrentTime, calcTimeSince, numFormatter } from '~/utils/dataFormatter'
import type { VideoPreviewResult } from '~/models/video/videoPreview'
@@ -38,9 +39,6 @@ interface Props {
moreBtn?: boolean
moreBtnActive?: boolean
removed?: boolean
showDislikeOptions?: boolean
feedbackReason?: { id: number, name: string }
dislikeReason?: { id: number, name: string }
}
const props = withDefaults(defineProps<Props>(), {
@@ -49,6 +47,8 @@ const props = withDefaults(defineProps<Props>(), {
const emit = defineEmits<{
(e: 'moreClick', event: MouseEvent): MouseEvent
(e: 'undo'): void
(e: 'tellUsWhy'): void
}>()
const videoUrl = computed(() => {
@@ -78,7 +78,6 @@ const wValue = computed((): string => {
return 'w-full'
})
const isDislike = ref<boolean>(false)
const isInWatchLater = ref<boolean>(false)
const isHover = ref<boolean>(false)
const contentVisibility = ref<'auto' | 'visible'>('auto')
@@ -153,6 +152,10 @@ function handelMouseLeave() {
function handleMoreBtnClick(event: MouseEvent) {
emit('moreClick', event)
}
function handleUndo() {
emit('undo')
}
</script>
<template>
@@ -163,19 +166,48 @@ function handleMoreBtnClick(event: MouseEvent) {
<div hidden w="xl:280px lg:250px md:200px 200px" />
<div hidden w="full" />
<template v-if="removed">
<div
:style="{ contentVisibility }"
w-full
pos="absolute top-0 left-0" aspect-video
>
<div :w="wValue" h-fit relative>
<img
:src="`${removeHttpFromUrl(cover)}@672w_378h_1c`" alt=""
w-full h-fit object-cover pos="absolute top-0 left-0" aspect-video
z--1 rounded="$bew-radius"
>
<div
pos="absolute top-0 left-0" w-full h-fit aspect-video flex="~ col gap-2 items-center justify-center"
bg="$bew-fill-4" backdrop-blur-20px mix-blend-luminosity rounded="$bew-radius"
>
<p mb-2 color-white text-lg>
{{ $t('home.video_removed') }}
</p>
<Button
color="rgba(255,255,255,.35)" text-color="white" size="small"
@click="handleUndo"
>
<template #left>
<Icon icon="mingcute:back-line" text-lg />
</template>
{{ $t('common.undo') }}
</Button>
</div>
</div>
</div>
</template>
<div
v-else
class="video-card group"
:class="isDislike ? 'is-dislike' : ''"
w="full" pos="absolute top-0 left-0"
rounded="$bew-radius" duration-300 ease-in-out
bg="hover:$bew-fill-2 active:$bew-fill-3" hover:ring="8 $bew-fill-2" active:ring="8 $bew-fill-3"
:style="{ contentVisibility }"
>
<template v-if="showDislikeOptions">
fdsflsd
</template>
<a
v-else
:style="{ display: horizontal ? 'flex' : 'block', gap: horizontal ? '1.5rem' : '0' }"
:href="videoUrl" target="_blank" rel="noopener noreferrer"
>
@@ -419,7 +451,7 @@ function handleMoreBtnClick(event: MouseEvent) {
<!-- skeleton -->
<template v-if="!horizontal">
<div
block mb-10 pointer-events-none select-none invisible
block mb-6 pointer-events-none select-none invisible
>
<!-- Cover -->
<div w-full shrink-0 aspect-video h-fit rounded="$bew-radius" />
@@ -451,7 +483,7 @@ function handleMoreBtnClick(event: MouseEvent) {
<template v-else>
<div
flex="~ gap-6"
mb-10 pointer-events-none select-none invisible
mb-6 pointer-events-none select-none invisible
>
<!-- Cover -->
<div
@@ -483,11 +515,11 @@ function handleMoreBtnClick(event: MouseEvent) {
</template>
<style lang="scss" scoped>
.video-card.is-dislike {
> *:not(#dislike-control) {
--at-apply: invisible pointer-events-none duration-0 transition-none;
}
}
// .video-card.is-dislike {
// > *:not(#dislike-control) {
// --at-apply: invisible pointer-events-none duration-0 transition-none;
// }
// }
.more-active {
--at-apply: opacity-100 bg-$bew-fill-3;

View File

@@ -15,7 +15,7 @@ const wValue = computed((): string => {
<template>
<div
v-if="!horizontal"
mb-8 pointer-events-none select-none
mb-6 pointer-events-none select-none
>
<div aspect-video bg="$bew-fill-4" rounded="$bew-radius" />
<div flex mt-4>
@@ -45,7 +45,7 @@ const wValue = computed((): string => {
<div
v-else
flex="~ gap-6"
mb-10 pointer-events-none select-none
mb-6 pointer-events-none select-none
>
<!-- By directly using predefined unocss width properties, it is possible to dynamically set the width attribute -->
<div hidden w="xl:280px lg:250px md:200px 200px" />