Skip to content

Commit

Permalink
feat: add wallpaper video player
Browse files Browse the repository at this point in the history
  • Loading branch information
WRXinYue committed Aug 23, 2024
1 parent 4747f7f commit fa29e98
Show file tree
Hide file tree
Showing 9 changed files with 105 additions and 16 deletions.
2 changes: 2 additions & 0 deletions demo/valaxy.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ export default defineConfig<ThemeConfig>({
'https://wrxinyue-images.s3.bitiful.net/wallpaper/Genshin Impact - Yae Miko (4) Cybust PC.mp4',
'https://wrxinyue-images.s3.bitiful.net/pc-wallpaper/wallhaven-yxwy7k.jpg',
],
playerUrl: 'https://valaxy-theme-sakura.s3.bitiful.net/PV/563098369-1-208.mp4',
// playerUrl: 'https://valaxy-theme-sakura.s3.bitiful.net/PV/Original PV Little love song MONGOL 800 cover by Amatsuki.mp4',
style: '',

typewriter: true,
Expand Down
Binary file added theme/assets/icon/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
83 changes: 72 additions & 11 deletions theme/components/SakuraBackgroundDisplay.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { isVideoUrl } from '../utils'
import { getLocalStorageItem, setLocalStorageItem } from '../utils/storage'
import { useSakuraAppStore } from '../stores'
import { useThemeConfig } from '../composables'
import playIconUrl from '../assets/icon/[email protected]'
import pauseIconUrl from '../assets/icon/[email protected]'
const props = withDefaults(defineProps<{
urls?: string[] | string
Expand All @@ -21,6 +23,8 @@ const themeConfig = useThemeConfig()
const urls = computed(() => props.urls || themeConfig.value.banner.urls || '')
const currentWallpaperUrl = computed(() => typeof urls.value === 'string' ? urls.value : urls.value[currentIndex.value])
const isCurrentMediaVideo = computed(() => isVideoUrl(currentWallpaperUrl.value))
const currentIconUrl = computed(() => sakura.isPlaying ? pauseIconUrl : playIconUrl)
const banner = computed(() => themeConfig.value.banner)
watch(() => sakura.wallpaperIndex[storageKey], (newIndex) => {
setLocalStorageItem(storageKey, newIndex!)
Expand All @@ -31,6 +35,10 @@ watch(() => urls.value.length, async (length) => {
sakura.wallpaperLength[storageKey] = length
})
function togglePlayPause() {
sakura.isPlaying = !sakura.isPlaying
}
onMounted(() => {
currentIndex.value = getLocalStorageItem(storageKey) || 0
sakura.wallpaperIndex[storageKey] = currentIndex.value
Expand All @@ -39,16 +47,69 @@ onMounted(() => {
</script>

<template>
<div class="sakura-background-display h-100vh w-full">
<template v-if="isCurrentMediaVideo">
<video :key="currentWallpaperUrl" class="block h-full w-full bg-cover object-cover" preload="auto" autoplay loop muted>
<source :src="currentWallpaperUrl" type="video/mp4">
Your browser does not support video tags
</video>
</template>
<template v-else>
<img v-if="currentWallpaperUrl" alt="Image Wallpaper" class="block h-full w-full bg-cover bg-center object-cover" :src="currentWallpaperUrl">
<div v-else class="default-wallpaper h-full w-full" />
</template>
<div class="sakura-background-display h-100vh w-full overflow-hidden">
<Transition
:name="sakura.wallpaperOperation === 'nextMedia' ? 'slide-right'
: sakura.wallpaperOperation === 'prevMedia' ? 'slide-left'
: 'fade'"
mode="out-in"
>
<template v-if="sakura.isPlaying || isCurrentMediaVideo">
<video
:key="sakura.isPlaying ? banner.playerUrl : currentWallpaperUrl"
class="min-h-full min-w-full object-cover"
preload="auto" autoplay :loop="!sakura.isPlaying" :muted="!sakura.isPlaying"
:disablePictureInPicture="banner.disablePictureInPicture"
@ended="sakura.isPlaying = false"
>
<source :src="sakura.isPlaying ? banner.playerUrl : currentWallpaperUrl" type="video/mp4">
Your browser does not support video tags
</video>
</template>
<template v-else>
<img v-if="currentWallpaperUrl" :key="currentWallpaperUrl" alt="Image Wallpaper" class="block h-full w-full bg-cover bg-center object-cover" :src="currentWallpaperUrl">
<div v-else class="default-wallpaper h-full w-full" />
</template>
</Transition>
</div>
<img :src="currentIconUrl" z-5 class="animation-fly absolute bottom-2 right-2 h-8 w-8 cursor-pointer" style="animation-duration: 2s; --translate-distance: 0.2em" @click="togglePlayPause">
</template>

<style lang="scss" scoped>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
.slide-right {
&-enter-active,
&-leave-active {
transition: transform 1s ease;
}
&-enter-from,
&-leave-to {
transform: translateX(-100%);
}
&-enter-to,
&-leave-from {
transform: translateX(0);
}
}
.slide-left-enter-active,
.slide-left-leave-active {
transition: transform 1s ease;
}
.slide-left-enter,
.slide-left-leave-to {
transform: translateX(100%);
}
</style>
10 changes: 8 additions & 2 deletions theme/components/SakuraBanner.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script lang="ts" setup>
import { computed } from 'vue'
import { useMounted } from '@vueuse/core'
import { useSakuraAppStore } from '../stores'
import { useThemeConfig } from '../composables'
import type { Banner } from '../types/index'
Expand All @@ -9,19 +10,24 @@ const props = defineProps<{
}>()
const themeConfig = useThemeConfig()
const sakura = useSakuraAppStore()
const isMounted = useMounted()
const banner = computed(() => props.banner || themeConfig.value.banner)
const overlayBarClass = computed(() => sakura.isPlaying ? 'animation-fade-out-down' : 'animation-fade-in-up')
</script>

<template>
<header class="sakura-banner <md:px-5">
<template v-if="isMounted">
<div class="absolute top-0 h-full w-full overflow-hidden" :class="[banner.style && 'banner-style', banner.style]">
<div class="absolute inset-0 overflow-hidden" :class="[banner.style && 'banner-style', banner.style]">
<slot name="background-display" />

<slot name="overlay-bar" />
<div :class="overlayBarClass">
<slot name="overlay-bar" />
</div>
</div>

<div z-4>
<slot name="info-overlay" />
</div>
Expand Down
12 changes: 10 additions & 2 deletions theme/components/themes/InfoOverlayThemeSakura.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,29 @@ const { hitokoto, fetchHitokoto } = useAddonHitokoto(themeConfig.value.banner.hi
const banner = computed(() => props.banner || themeConfig.value.banner)
function prevMedia() {
sakura.wallpaperOperation = 'prevMedia'
sakura.wallpaperIndex[storageKey] = (sakura.wallpaperIndex[storageKey] - 1 + sakura.wallpaperLength[storageKey]) % sakura.wallpaperLength[storageKey]
setTimeout(() => {
sakura.wallpaperOperation = ''
}, 0)
}
function nextMedia() {
sakura.wallpaperOperation = 'nextMedia'
sakura.wallpaperIndex[storageKey] = (sakura.wallpaperIndex[storageKey] + 1) % sakura.wallpaperLength[storageKey]
setTimeout(() => {
sakura.wallpaperOperation = ''
}, 0)
}
</script>

<template>
<div class="info-overlay-theme-sakura">
<slot name="highlighted-text">
<SakuraGlitchText :text="banner.title" />
<SakuraGlitchText :class="sakura.isPlaying ? 'animation-fade-out-up' : 'animation-fade-in-down'" :text="banner.title" />
</slot>

<div class="card-wrapper">
<div class="card-wrapper" :class="sakura.isPlaying ? 'animation-slit-out-horizontal' : 'animation-slit-in-horizontal'">
<slot name="muted-text">
<div class="flex justify-center">
<span class="inline-block" i-fa6-solid-quote-left />
Expand Down
2 changes: 2 additions & 0 deletions theme/node/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export const defaultThemeConfig: ThemeConfig = {

typewriter: false,
enableHitokoto: false,

disablePictureInPicture: false,
},

navbar: [],
Expand Down
4 changes: 3 additions & 1 deletion theme/stores/wallpaper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { ref } from 'vue'
export function useWallpaper() {
const wallpaperIndex = ref<{ [key: string]: number }>({})
const wallpaperLength = ref<{ [key: string]: number }>({})
const wallpaperOperation = ref<'prevMedia' | 'nextMedia' | ''>()
const isPlaying = ref(false)

return { wallpaperIndex, wallpaperLength }
return { wallpaperIndex, wallpaperLength, wallpaperOperation, isPlaying }
}
8 changes: 8 additions & 0 deletions theme/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,14 @@ export interface Banner {
* @default undefined
*/
waveTheme?: 'fish' | 'horizontal' | 'ripple' | 'yunCloud'

/**
* @zh 自定义视频, 可以放PV MV之类的
* @en Custom Video
*/
playerUrl?: string

disablePictureInPicture?: boolean
}

export type SidebarMulti = (string | SidebarItem)[]
Expand Down

0 comments on commit fa29e98

Please sign in to comment.