Skip to content

Commit

Permalink
feat: add custom enhancements (#360)
Browse files Browse the repository at this point in the history
* feat: add custom enhancements

feat: Add configuration to hide lyrics on startup

feat: Add auto-hide configuration for APlayer

feat: Add configuration to show APlayer after loading is complete

* docs: update configuration items

* refactor: add unmounted for eventListerner & observer

* refactor: change the code specification

* refactor: change onMounted and add unmounted for observer & eventListerner

---------

Co-authored-by: YunYouJun <me@yunyoujun.cn>
  • Loading branch information
WRXinYue and YunYouJun committed Feb 24, 2024
1 parent 252d539 commit eb29e9b
Show file tree
Hide file tree
Showing 9 changed files with 228 additions and 1 deletion.
22 changes: 22 additions & 0 deletions packages/valaxy-addon-meting/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,28 @@ export default defineConfig({
})
```

```ts
export interface MetingOptions {
global?: boolean
/** @see https://github.com/metowolf/MetingJS#option */
props?: {
id?: string
server?: 'netease' | 'tencent' | 'kugou' | 'xiami' | 'baidu'
type?: 'song' | 'album' | 'artist' | 'playlist' | 'search'
}
options?: {
animationIn?: boolean
autoHidden?: boolean
lyricHidden?: boolean
}
}
```
| Configuration Item | Description | Default Value |
| ------------------------------------- | -------------------------------------------------------------------------------------------------- | ------------- |
| **lyricsLoadOnStart** (optional) | Specifies whether to hide the lyrics upon startup | `false` |
| **aplayerAutoHide** (optional) | Enables auto-hiding of the APlayer interface when not interacted with. Recommended for use with `aplayerVisibleAfterLoad` | `false` |
| **aplayerVisibleAfterLoad** (optional) | Determines whether the APlayer interface should be visible immediately after loading is complete | `false` |

## props

You can [meting#options](https://github.com/metowolf/MetingJS#option)
Expand Down
34 changes: 34 additions & 0 deletions packages/valaxy-addon-meting/client/hook.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import type { MetingOptions } from '../node/index'
import { animationIn, autoHidden, handleOptions, useAPlayerMiniSwitcherEventListener } from './utils'
import { setupHiddenLyricHidingObserver } from './observer'

export enum Hook {
metingInit = 'metingInit',
metingLoadBefore = 'metingLoadBefore',
metingLoad = 'metingLoad',
}

export function onMetingInit({ options }: MetingOptions) {
handleOptions(options, {
animationIn: () => import('../style/animation-in.scss'),
})
}

export function onMetingLoadBefore({ options }: MetingOptions) {
handleOptions(options, {
animationIn: () => animationIn(Hook.metingLoadBefore),
})
}

export function onMetingLoad({ options }: MetingOptions) {
handleOptions(options, {
lyricHidden: () => setupHiddenLyricHidingObserver(),
animationIn: () => {
animationIn(Hook.metingLoad)
},
autoHidden: () => {
useAPlayerMiniSwitcherEventListener()
autoHidden(Hook.metingLoad)
},
})
}
11 changes: 10 additions & 1 deletion packages/valaxy-addon-meting/client/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { useScriptTag } from '@vueuse/core'
import { useHead } from '@unhead/vue'
import { computed } from 'vue'
import { computed, onMounted } from 'vue'
import { useSiteConfig } from 'valaxy'
import { useMetingLoadObserver } from './observer'
import { useAddonMeting } from './options'
import { onMetingInit } from './hook'

/**
* use MetingJS and Aplayer
Expand All @@ -10,6 +13,7 @@ import { useSiteConfig } from 'valaxy'
*/
export function useMeting() {
const siteConfig = useSiteConfig()
const addonMeting = useAddonMeting()
const cdnPrefix = computed(() => siteConfig.value.cdn.prefix)

useHead({
Expand All @@ -25,4 +29,9 @@ export function useMeting() {
useScriptTag(`${cdnPrefix.value}aplayer/dist/APlayer.min.js`, () => {
useScriptTag(`${cdnPrefix.value}meting@2/dist/Meting.min.js`)
})

onMounted(() => {
onMetingInit(addonMeting.value)
useMetingLoadObserver(addonMeting.value)
})
}
64 changes: 64 additions & 0 deletions packages/valaxy-addon-meting/client/observer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { onUnmounted } from 'vue'
import type { MetingOptions } from '../node/index'
import { onMetingLoad, onMetingLoadBefore } from './hook'

export function setupHiddenLyricHidingObserver() {
let observer: MutationObserver | null

observer = new MutationObserver((mutations) => {
const lrcElement = document.querySelector('.aplayer-lrc .aplayer-lrc-contents .aplayer-lrc-current') as HTMLElement
const lrcButton = document.querySelector('.aplayer-icon-lrc') as HTMLElement
function removelrc() {
if (lrcElement) {
lrcElement.style.display = 'none'
if (lrcElement.textContent !== 'Loading') {
lrcButton.click()
lrcElement.style.display = ''
observer?.disconnect()
}
}
}
mutations.forEach((_mutation) => {
removelrc()
})
})
observer.observe(document.body, { childList: true, subtree: true })

onUnmounted(() => {
observer?.disconnect()
observer = null
})
}

export function useMetingLoadObserver(addon: MetingOptions) {
let hasExecuted = false
let observer: MutationObserver | null

observer = new MutationObserver((mutations) => {
function load() {
if (hasExecuted)
return
const aplayerNarrowElement = document.querySelector('.aplayer.aplayer-fixed.aplayer-narrow .aplayer-body') as HTMLElement
if (aplayerNarrowElement) {
hasExecuted = true
setTimeout(() => {
onMetingLoadBefore(addon)
requestAnimationFrame(() => {
onMetingLoad(addon)
observer?.disconnect()
observer = null
})
}, 0)
}
}
mutations.forEach((_mutation) => {
load()
})
})
observer.observe(document.body, { childList: true, subtree: true })

onUnmounted(() => {
observer?.disconnect()
observer = null
})
}
13 changes: 13 additions & 0 deletions packages/valaxy-addon-meting/client/options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { computed } from 'vue'
import { useRuntimeConfig } from 'valaxy'
import type { MetingOptions } from '../node/index'

/**
* get addon config
*/
export function useAddonMeting() {
const runtimeConfig = useRuntimeConfig()
return computed<MetingOptions>(() => {
return runtimeConfig.value.addons['valaxy-addon-meting'] as unknown as MetingOptions
})
}
72 changes: 72 additions & 0 deletions packages/valaxy-addon-meting/client/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { useEventListener } from '@vueuse/core'
import { onMounted, onUnmounted } from 'vue'
import type { MetingOptions } from '../node/index'
import { Hook } from './hook'

type Rules = {
[K in string]: () => void;
}
export function handleOptions(options: MetingOptions['options'], rules: Rules) {
if (!options)
return
Object.entries(rules).forEach(([key, action]) => {
if (options[key as keyof typeof options])
action()
})
}

/**
* APlayer mini switcher
*/
export function useAPlayerMiniSwitcherEventListener() {
let aplayerFixedElement: HTMLElement
let aplayerIconButton: HTMLElement
let aplayerNarrow = true

function toggleAplayerVisibility() {
aplayerNarrow = !aplayerNarrow
}

function hiddenAplayer() {
if (aplayerNarrow)
aplayerFixedElement.style.left = '-66px'
}

function showAplayer() {
aplayerFixedElement.style.left = '0'
}

onMounted(() => {
aplayerFixedElement = document.querySelector('.aplayer.aplayer-fixed .aplayer-body') as HTMLElement
aplayerIconButton = document.querySelector('.aplayer-body .aplayer-miniswitcher .aplayer-icon') as HTMLElement

useEventListener(aplayerFixedElement, 'mouseenter', showAplayer)
useEventListener(aplayerFixedElement, 'mouseleave', hiddenAplayer)
useEventListener(aplayerIconButton, 'click', toggleAplayerVisibility)
})

onUnmounted(() => {
aplayerFixedElement?.removeEventListener('mouseenter', showAplayer)
aplayerFixedElement?.removeEventListener('mouseleave', hiddenAplayer)
aplayerIconButton?.removeEventListener('click', toggleAplayerVisibility)
})
}

function handleAplayerAction(action: string, leftValue: string) {
const aplayerNarrowElement = document.querySelector('.aplayer.aplayer-fixed.aplayer-narrow .aplayer-body') as HTMLElement
if (!aplayerNarrowElement)
return

if (action === Hook.metingLoadBefore)
aplayerNarrowElement.style.display = 'initial'
else if (action === Hook.metingLoad)
aplayerNarrowElement.style.left = leftValue
}

export function animationIn(action: string) {
handleAplayerAction(action, '0')
}

export function autoHidden(action: string) {
handleAplayerAction(action, '-66px')
}
2 changes: 2 additions & 0 deletions packages/valaxy-addon-meting/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './client'
export * from './node'
5 changes: 5 additions & 0 deletions packages/valaxy-addon-meting/node/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ export interface MetingOptions {
'storage-name'?: string
[key: string]: any
}
options?: {
animationIn?: boolean
autoHidden?: boolean
lyricHidden?: boolean
}
}

export const addonMeting = defineValaxyAddon<MetingOptions>(options => ({
Expand Down
6 changes: 6 additions & 0 deletions packages/valaxy-addon-meting/style/animation-in.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.aplayer.aplayer-fixed.aplayer-narrow {
& .aplayer-body {
display: none;
left: -100px;
}
}

0 comments on commit eb29e9b

Please sign in to comment.