This commit is contained in:
lyswhut
2022-10-29 11:36:35 +08:00
parent 66b965d9f7
commit e45cee6596
715 changed files with 57096 additions and 31771 deletions
@@ -0,0 +1,136 @@
<template>
<ul ref="dom_lists_list" class="scroll" :class="$style.listsContent">
<li
v-for="(item, index) in list"
:key="item.id" :class="[$style.listsItem, { [$style.active]: item.id == boardId }, { [$style.clicked]: rightClickItemIndex == index }]"
:aria-label="item.name" @click="handleToggleList(item.id)" @contextmenu="handleRigthClick($event, index)"
>
<span :class="$style.listsLabel">{{ item.name }}</span>
</li>
</ul>
<base-menu
v-model="isShowMenu"
:menus="menus"
:xy="menuLocation"
item-name="name"
@menu-click="handleMenuClick"
/>
</template>
<script setup lang="ts">
import { watch, shallowReactive, ref, defineExpose } from '@common/utils/vueTools'
import { getBoardsList, setBoard } from '@renderer/store/leaderboard/action'
import { boards, Board } from '@renderer/store/leaderboard/state'
import useMenu from './useMenu'
import LX from '@renderer/types/lx'
import { useRouter, useRoute } from '@common/utils/vueRouter'
const props = defineProps<{
source: LX.OnlineSource
boardId?: string
}>()
const emit = defineEmits(['show-menu'])
const router = useRouter()
const route = useRoute()
const list = shallowReactive<Board['list']>([])
const rightClickItemIndex = ref(-1)
const handleToggleList = (id: string) => {
router.replace({
path: route.path,
query: {
source: props.source,
boardId: id,
},
})
}
const {
menus,
menuLocation,
isShowMenu,
showMenu,
menuClick,
} = useMenu({ emit, list })
const handleRigthClick = (event: MouseEvent, index: number) => {
rightClickItemIndex.value = index
showMenu(event, index)
}
const handleMenuClick = (action?: { action: string}) => {
if (rightClickItemIndex.value < 0) return
let index = rightClickItemIndex.value
rightClickItemIndex.value = -1
menuClick(action, index, props.source)
}
watch(() => props.source, async(source) => {
// const source = (await getLeaderboardSetting()).source as LX.OnlineSource
let boardList = boards[source]
if (boardList == null) setBoard(boardList = await getBoardsList(source), source)
list.splice(0, list.length, ...boardList.list)
if (!props.boardId && boardList.list.length) handleToggleList(boardList.list[0].id)
}, {
immediate: true,
})
defineExpose({ hideMenu: handleMenuClick })
</script>
<style lang="less" module>
@import '@renderer/assets/styles/layout.less';
.listsContent {
flex: auto;
min-width: 0;
overflow-y: scroll;
// overflow-y: scroll !important;
// border-right: 1px solid rgba(0, 0, 0, 0.12);
}
.listsItem {
position: relative;
transition: .3s ease;
transition-property: color, background-color;
background-color: transparent;
&:hover:not(.active) {
background-color: var(--color-primary-background-hover);
cursor: pointer;
}
&.active {
// background-color:
color: var(--color-primary);
}
&.selected {
background-color: var(--color-primary-font-active);
}
&.clicked {
background-color: var(--color-primary-background-hover);
}
&.editing {
padding: 0 10px;
background-color: var(--color-primary-background-hover);
.listsLabel {
display: none;
}
.listsInput {
display: block;
}
}
}
.listsLabel {
display: block;
height: 100%;
padding: 0 10px;
font-size: 13px;
line-height: 36px;
.mixin-ellipsis-1;
}
</style>
@@ -0,0 +1,72 @@
import { computed, ref, reactive, nextTick } from '@common/utils/vueTools'
import { useI18n } from '@renderer/plugins/i18n'
import { addSongListDetail, playSongListDetail } from '../action'
export default ({
emit,
list,
}) => {
// const menuControl = reactive({
// play: true,
// collect: true,
// })
const t = useI18n()
const menuLocation = reactive({ x: 0, y: 0 })
const isShowMenu = ref(false)
const menus = computed(() => {
return [
{
name: t('list__play'),
action: 'play',
disabled: false,
},
{
name: t('list__collect'),
action: 'collect',
disabled: false,
},
]
})
const showMenu = (event, index) => {
menuLocation.x = event.pageX
menuLocation.y = event.pageY
if (isShowMenu.value) return
emit('show-menu')
nextTick(() => {
isShowMenu.value = true
})
}
const hideMenu = () => {
isShowMenu.value = false
}
const menuClick = (action, index, source) => {
// console.log(action)
hideMenu()
if (!action) return
// const id = `board__${this.source}__${board.id}`
const board = list[index]
switch (action.action) {
case 'play':
playSongListDetail(board.id)
break
case 'collect':
addSongListDetail(board.id, board.name, source)
break
}
}
return {
menus,
menuLocation,
isShowMenu,
showMenu,
menuClick,
}
}
@@ -0,0 +1,78 @@
<template>
<div :class="$style.container">
<material-online-list
ref="listRef"
:page="listDetailInfo.page"
:limit="listDetailInfo.limit"
:total="listDetailInfo.total"
:list="listDetailInfo.list"
:no-item="listDetailInfo.noItemLabel"
@show-menu="hideListsMenu"
@play-list="handlePlayList"
@toggle-page="togglePage"
/>
</div>
</template>
<script setup lang="ts">
import { watch, defineProps, defineExpose } from '@common/utils/vueTools'
import LX from '@renderer/types/lx'
import useList from './useList'
const props = defineProps<{
source: LX.OnlineSource
boardId?: string
}>()
const emit = defineEmits(['show-menu'])
const {
listRef,
listDetailInfo,
getList,
handlePlayList,
} = useList()
watch(() => props.boardId, (boardId) => {
if (!boardId) return
getList(boardId, 1)
}, {
immediate: true,
})
const hideListsMenu = () => {
emit('show-menu')
}
const togglePage = (page: number) => {
getList(listDetailInfo.id, page)
}
const hideMenu = () => {
listRef.value.handleMenuClick()
}
defineExpose({ hideMenu })
</script>
<style lang="less" module>
.container {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
.list {
overflow: hidden;
height: 100%;
flex: auto;
}
</style>
@@ -0,0 +1,29 @@
import { ref } from '@common/utils/vueTools'
// import { useI18n } from '@renderer/plugins/i18n'
// import { } from '@renderer/store/search/state'
import { getAndSetListDetail } from '@renderer/store/leaderboard/action'
import { listDetailInfo } from '@renderer/store/leaderboard/state'
import { playSongListDetail } from '../action'
export default () => {
const listRef = ref<any>(null)
const handlePlayList = (index: number) => {
void playSongListDetail(listDetailInfo.id, listDetailInfo.list, index)
}
const getList = (id: string, page: number) => {
void getAndSetListDetail(id, page).then(() => {
setTimeout(() => {
if (listRef.value) listRef.value.scrollToTop()
})
})
}
return {
listRef,
listDetailInfo,
getList,
handlePlayList,
}
}
+57
View File
@@ -0,0 +1,57 @@
import { tempListMeta, userLists } from '@renderer/store/list/state'
import { dialog } from '@renderer/plugins/Dialog'
import syncSourceList from '@renderer/store/list/syncSourceList'
import { getListDetail, getListDetailAll } from '@renderer/store/leaderboard/action'
import { createUserList, setTempList } from '@renderer/store/list/action'
import { playList } from '@renderer/core/player/action'
import { LIST_IDS } from '@common/constants'
const getListId = (id: string) => `board__${id}`
export const addSongListDetail = async(id: string, name: string, source: LX.OnlineSource) => {
// console.log(this.listDetail.info)
// if (!this.listDetail.info.name) return
const listId = getListId(id)
const targetList = userLists.find(l => l.id == listId)
if (targetList) {
const confirm = await dialog.confirm({
message: window.i18n.t('duplicate_list_tip', { name: targetList.name }),
cancelButtonText: window.i18n.t('lists__import_part_button_cancel'),
confirmButtonText: window.i18n.t('confirm_button_text'),
})
if (!confirm) return
void syncSourceList(targetList)
return
}
const list = await getListDetailAll(id)
await createUserList({
name,
id: listId,
list,
source,
sourceListId: listId,
})
}
export const playSongListDetail = async(id: string, list?: LX.Music.MusicInfoOnline[], index: number = 0) => {
let isPlayingList = false
console.log(list)
const listId = getListId(id)
if (!list?.length) list = (await getListDetail(id, 1)).list
if (list?.length) {
await setTempList(listId, [...list])
playList(LIST_IDS.TEMP, index)
isPlayingList = true
}
const fullList = await getListDetailAll(id)
if (!fullList.length) return
if (isPlayingList) {
if (tempListMeta.id == listId) {
await setTempList(listId, [...fullList])
}
} else {
await setTempList(listId, [...fullList])
playList(LIST_IDS.TEMP, index)
}
}
+189
View File
@@ -0,0 +1,189 @@
<template>
<div :class="$style.leaderboard">
<div :class="$style.lists">
<div :class="$style.listsSelect">
<base-selection :model-value="source" :class="$style.select" :list="sourceList" item-key="id" item-name="name" @update:model-value="handleToggleSource" />
</div>
<BoardList ref="boardListRef" :board-id="boardId" :source="source" @show-menu="$refs.musicListRef?.hideMenu()" />
</div>
<div :class="$style.list">
<MusicList ref="musicListRef" :source="source" :board-id="boardId" @show-menu="$refs.boardListRef?.hideMenu()" />
</div>
</div>
</template>
<script>
import { computed, ref } from '@common/utils/vueTools'
import { getLeaderboardSetting, setLeaderboardSetting } from '@renderer/utils/data'
import BoardList from './BoardList/index.vue'
import MusicList from './MusicList/index.vue'
import { sources } from '@renderer/store/leaderboard/state'
import { sourceNames } from '@renderer/store'
import { useRoute, useRouter } from '@common/utils/vueRouter'
const source = ref('')
const boardId = ref(null)
const verifyQueryParams = async function(to, from, next) {
let _source = to.query.source
let _boardId = to.query.boardId
if (_source == null) {
const setting = await getLeaderboardSetting()
if (_source == null) {
_source = setting.source
_boardId = setting.boardId
}
next({
path: to.path,
query: { ...to.query, source: _source, boardId: _boardId },
})
return
}
next()
source.value = _source
boardId.value = _boardId
setLeaderboardSetting({ source: _source, boardId: _boardId })
}
export default {
components: {
BoardList,
MusicList,
},
beforeRouteEnter: verifyQueryParams,
beforeRouteUpdate: verifyQueryParams,
setup() {
const musicListRef = ref(null)
const boardListRef = ref(null)
const sourceList = computed(() => {
return sources.map(s => ({ id: s, name: sourceNames.value[s] }))
})
const router = useRouter()
const route = useRoute()
const handleToggleSource = (id) => {
router.replace({
path: route.path,
query: {
source: id,
},
})
}
return {
source,
boardId,
sourceList,
handleToggleSource,
musicListRef,
boardListRef,
}
},
}
</script>
<style lang="less" module>
@import '@renderer/assets/styles/layout.less';
.leaderboard {
height: 100%;
display: flex;
position: relative;
}
.header {
flex: none;
width: 100%;
display: flex;
flex-flow: row nowrap;
}
.tab {
flex: auto;
}
.select {
flex: none;
width: 80px;
}
.content {
flex: auto;
display: flex;
overflow: hidden;
flex-flow: column nowrap;
}
.lists {
flex: none;
width: 14.8%;
display: flex;
flex-flow: column nowrap;
}
.listsHeader {
position: relative;
}
.listsSelect {
font-size: 12px;
&:hover {
:global(.icon) {
opacity: 1;
}
}
>:global(.content) {
display: block;
width: 100%;
}
:global(.label-content) {
background-color: transparent !important;
line-height: 38px;
height: 38px;
border-radius: 0;
&:hover {
background: none !important;
}
}
:global(.label) {
color: var(--color-font) !important;
}
:global(.icon) {
opacity: .6;
transition: opacity .3s ease;
}
:global(.selection-list) {
max-height: 500px;
box-shadow: 0 1px 8px 0 rgba(0,0,0,.2);
li {
// background-color: var(--color-main-background);
line-height: 38px;
font-size: 13px;
&:hover {
background-color: var(--color-button-background-hover);
}
&:active {
background-color: var(--color-button-background-active);
}
}
}
// line-height: 38px;
// padding: 0 10px;
border-bottom: var(--color-list-header-border-bottom);
flex: none;
}
.list {
position: relative;
overflow: hidden;
height: 100%;
flex: auto;
display: flex;
flex-flow: column nowrap;
// .noItem {
// }
}
</style>