升级到 vue3
This commit is contained in:
@@ -1,299 +0,0 @@
|
||||
<template lang="pug">
|
||||
div(:class="$style.aside")
|
||||
div(:class="$style.controlBtn" v-if="setting.controlBtnPosition == 'left'")
|
||||
button(type="button" :class="$style.close" :tips="$t('core.toolbar.close')" @click="close")
|
||||
svg(:class="$style.controlBtniIcon" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='100%' viewBox='0 0 24 24' space='preserve')
|
||||
use(xlink:href='#icon-window-close')
|
||||
button(type="button" :class="$style.min" :tips="$t('core.toolbar.min')" @click="min")
|
||||
svg(:class="$style.controlBtniIcon" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='100%' viewBox='0 0 24 24' space='preserve')
|
||||
use(xlink:href='#icon-window-minimize')
|
||||
|
||||
div(:class="['animated', logoAnimate, $style.logo]" v-else) L X
|
||||
//- svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='100%' height='100%' viewBox='0 0 127 61' space='preserve')
|
||||
use(xlink:href='#icon-logo')
|
||||
|
||||
div(:class="$style.menu")
|
||||
dl
|
||||
//- dt {{$t('core.aside.online_music')}}
|
||||
dd
|
||||
router-link(:active-class="$style.active" to="search" :tips="$t('core.aside.search')")
|
||||
div(:class="$style.icon")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' viewBox='0 0 425.2 425.2' space='preserve')
|
||||
use(xlink:href='#icon-search-2')
|
||||
dd
|
||||
router-link(:active-class="$style.active" to="songList" :tips="$t('core.aside.song_list')")
|
||||
div(:class="$style.icon")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' viewBox='0 0 425.2 425.2' space='preserve')
|
||||
use(xlink:href='#icon-album')
|
||||
//- span {{$t('core.aside.song_list')}}
|
||||
dd
|
||||
router-link(:active-class="$style.active" to="leaderboard" :tips="$t('core.aside.leaderboard')")
|
||||
div(:class="$style.icon")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' viewBox='0 0 425.22 425.2' space='preserve')
|
||||
use(xlink:href='#icon-leaderboard')
|
||||
//- span {{$t('core.aside.leaderboard')}}
|
||||
dl
|
||||
//- dt {{$t('core.aside.my_music')}}
|
||||
dd
|
||||
router-link(:active-class="$style.active" to="list" :tips="$t('core.aside.my_list')")
|
||||
div(:class="$style.icon")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' viewBox='0 0 444.87 391.18' space='preserve')
|
||||
use(xlink:href='#icon-love')
|
||||
dl
|
||||
//- dt {{$t('core.aside.other')}}
|
||||
dd(v-if="setting.download.enable")
|
||||
router-link(:active-class="$style.active" to="download" :tips="$t('core.aside.download')")
|
||||
div(:class="$style.icon")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' viewBox='0 0 425.2 425.2' space='preserve')
|
||||
use(xlink:href='#icon-download-2')
|
||||
//- span {{$t('core.aside.download')}}
|
||||
dd
|
||||
router-link(:active-class="$style.active" to="setting" :tips="$t('core.aside.setting')")
|
||||
div(:class="$style.icon")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' viewBox='0 0 493.23 436.47' space='preserve')
|
||||
use(xlink:href='#icon-setting')
|
||||
//- span {{$t('core.aside.setting')}}
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import { base as eventBaseName } from '../../event/names'
|
||||
// import { getRandom } from '../../utils'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
active: 'search',
|
||||
animates: [
|
||||
'bounce',
|
||||
// 'flash',
|
||||
// 'pulse',
|
||||
'rubberBand',
|
||||
// 'shake',
|
||||
// 'headShake',
|
||||
'swing',
|
||||
'tada',
|
||||
// 'wobble',
|
||||
'jello',
|
||||
// 'heartBeat',
|
||||
],
|
||||
logoAnimate: '',
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['setting']),
|
||||
...mapGetters('list', ['defaultList']),
|
||||
},
|
||||
// mounted() {
|
||||
// this.logoAnimate = this.animates[getRandom(0, this.animates.length)]
|
||||
// },
|
||||
methods: {
|
||||
// handleMouseEnter() {
|
||||
// console.log('object')
|
||||
// this.logoAnimate = this.animates[getRandom(0, this.animates.length)]
|
||||
// },
|
||||
min() {
|
||||
window.eventHub.$emit(eventBaseName.min)
|
||||
},
|
||||
max() {
|
||||
window.eventHub.$emit(eventBaseName.max)
|
||||
},
|
||||
close() {
|
||||
window.eventHub.$emit(eventBaseName.close)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="less" module>
|
||||
@import '../../assets/styles/layout.less';
|
||||
|
||||
.aside {
|
||||
// box-shadow: 0 0 5px rgba(0, 0, 0, .3);
|
||||
transition: @transition-theme;
|
||||
transition-property: background-color;
|
||||
background-color: @color-theme-sidebar;
|
||||
// background-color: @color-aside-background;
|
||||
// border-right: 2px solid @color-theme;
|
||||
-webkit-app-region: drag;
|
||||
-webkit-user-select: none;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
}
|
||||
|
||||
@control-btn-width: @height-toolbar * .26;
|
||||
@control-btn-height: 6%;
|
||||
.controlBtn {
|
||||
box-sizing: border-box;
|
||||
padding: 0 7px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-evenly;
|
||||
width: 100%;
|
||||
height: @control-btn-height;
|
||||
-webkit-app-region: no-drag;
|
||||
opacity: .5;
|
||||
transition: opacity @transition-theme;
|
||||
&:hover {
|
||||
opacity: .8;
|
||||
.controlBtniIcon {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
position: relative;
|
||||
width: @control-btn-width;
|
||||
height: @control-btn-width;
|
||||
background: none;
|
||||
border: none;
|
||||
display: flex;
|
||||
// justify-content: center;
|
||||
// align-items: center;
|
||||
outline: none;
|
||||
padding: 1px;
|
||||
cursor: pointer;
|
||||
border-radius: 50%;
|
||||
color: @color-theme_2;
|
||||
|
||||
&.min {
|
||||
background-color: @color-minBtn;
|
||||
}
|
||||
&.max {
|
||||
background-color: @color-maxBtn;
|
||||
}
|
||||
&.close {
|
||||
background-color: @color-closeBtn;
|
||||
}
|
||||
}
|
||||
}
|
||||
.controlBtniIcon {
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.logo {
|
||||
box-sizing: border-box;
|
||||
padding: 0 13%;
|
||||
height: 50px;
|
||||
color: @color-theme-font;
|
||||
flex: none;
|
||||
text-align: center;
|
||||
line-height: 50px;
|
||||
font-weight: bold;
|
||||
// -webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
.menu {
|
||||
flex: auto;
|
||||
// &.controlBtnLeft {
|
||||
// display: flex;
|
||||
// flex-flow: column nowrap;
|
||||
// justify-content: center;
|
||||
// padding-bottom: @control-btn-height;
|
||||
// }
|
||||
// padding: 5px;
|
||||
dl {
|
||||
-webkit-app-region: no-drag;
|
||||
// margin-bottom: 15px;
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
dt {
|
||||
padding-left: 5px;
|
||||
font-size: 11px;
|
||||
transition: @transition-theme;
|
||||
transition-property: color;
|
||||
color: @color-theme-font-label;
|
||||
.mixin-ellipsis-1;
|
||||
}
|
||||
dd a {
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
text-decoration: none;
|
||||
|
||||
position: relative;
|
||||
padding: 18px 3px;
|
||||
// margin: 5px 0;
|
||||
// border-left: 5px solid transparent;
|
||||
transition: @transition-theme;
|
||||
transition-property: color;
|
||||
color: @color-theme-font;
|
||||
cursor: pointer;
|
||||
font-size: 11.5px;
|
||||
text-align: center;
|
||||
outline: none;
|
||||
|
||||
transition: background-color 0.3s ease;
|
||||
// border-radius: @radius-border;
|
||||
.mixin-ellipsis-1;
|
||||
|
||||
&.active {
|
||||
// border-left-color: @color-theme-active;
|
||||
background-color: @color-theme-active;
|
||||
}
|
||||
|
||||
&:hover:not(.active) {
|
||||
background-color: @color-theme-hover;
|
||||
}
|
||||
&:hover:not(.active) {
|
||||
background-color: @color-theme-active;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
// margin-bottom: 5px;
|
||||
&> svg {
|
||||
width: 32%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
each(@themes, {
|
||||
:global(#container.@{value}) {
|
||||
.aside {
|
||||
background-color: ~'@{color-@{value}-theme-sidebar}';
|
||||
}
|
||||
.controlBtn {
|
||||
button {
|
||||
color: ~'@{color-@{value}-theme_2}';
|
||||
|
||||
&.min {
|
||||
background-color: ~'@{color-@{value}-minBtn}';
|
||||
}
|
||||
&.max {
|
||||
background-color: ~'@{color-@{value}-maxBtn}';
|
||||
}
|
||||
&.close {
|
||||
background-color: ~'@{color-@{value}-closeBtn}';
|
||||
}
|
||||
}
|
||||
}
|
||||
.logo {
|
||||
color: ~'@{color-@{value}-theme-font}';
|
||||
}
|
||||
.menu {
|
||||
dl {
|
||||
dt {
|
||||
color: ~'@{color-@{value}-theme-font-label}';
|
||||
}
|
||||
dd a {
|
||||
color: ~'@{color-@{value}-theme-font}';
|
||||
&.active {
|
||||
background-color: ~'@{color-@{value}-theme-active}';
|
||||
}
|
||||
&:hover:not(.active) {
|
||||
background-color: ~'@{color-@{value}-theme-hover}';
|
||||
}
|
||||
&:active:not(.active) {
|
||||
background-color: ~'@{color-@{value}-theme-active}';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,111 @@
|
||||
<template>
|
||||
<div :class="$style.controlBtn">
|
||||
<button type="button" :class="[$style.btn, $style.close]" :tips="$t('close')" @click="close">
|
||||
<svg :class="$style.controlBtniIcon" version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" width="100%" viewBox="0 0 24 24" space="preserve">
|
||||
<use xlink:href="#icon-window-close"></use>
|
||||
</svg>
|
||||
</button>
|
||||
<button type="button" :class="[$style.btn, $style.min]" :tips="$t('min')" @click="min">
|
||||
<svg :class="$style.controlBtniIcon" version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" width="100%" viewBox="0 0 24 24" space="preserve">
|
||||
<use xlink:href="#icon-window-minimize"></use>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { base as eventBaseName } from '@renderer/event/names'
|
||||
// import { getRandom } from '../../utils'
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
return {
|
||||
min() {
|
||||
window.eventHub.emit(eventBaseName.min)
|
||||
},
|
||||
max() {
|
||||
window.eventHub.emit(eventBaseName.max)
|
||||
},
|
||||
close() {
|
||||
window.eventHub.emit(eventBaseName.close)
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" module>
|
||||
@import '@renderer/assets/styles/layout.less';
|
||||
|
||||
@control-btn-width: @height-toolbar * .26;
|
||||
@control-btn-height: 6%;
|
||||
.controlBtn {
|
||||
box-sizing: border-box;
|
||||
padding: 0 7px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-evenly;
|
||||
width: 100%;
|
||||
height: @control-btn-height;
|
||||
-webkit-app-region: no-drag;
|
||||
opacity: .5;
|
||||
transition: opacity @transition-theme;
|
||||
&:hover {
|
||||
opacity: .8;
|
||||
.controlBtniIcon {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
.btn {
|
||||
position: relative;
|
||||
width: @control-btn-width;
|
||||
height: @control-btn-width;
|
||||
background: none;
|
||||
border: none;
|
||||
display: flex;
|
||||
// justify-content: center;
|
||||
// align-items: center;
|
||||
outline: none;
|
||||
padding: 1px;
|
||||
cursor: pointer;
|
||||
border-radius: 50%;
|
||||
color: @color-theme_2;
|
||||
|
||||
&.min {
|
||||
background-color: @color-minBtn;
|
||||
}
|
||||
&.max {
|
||||
background-color: @color-maxBtn;
|
||||
}
|
||||
&.close {
|
||||
background-color: @color-closeBtn;
|
||||
}
|
||||
}
|
||||
|
||||
.controlBtniIcon {
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
|
||||
each(@themes, {
|
||||
:global(#root.@{value}) {
|
||||
.btn {
|
||||
color: ~'@{color-@{value}-theme_2}';
|
||||
|
||||
&.min {
|
||||
background-color: ~'@{color-@{value}-minBtn}';
|
||||
}
|
||||
&.max {
|
||||
background-color: ~'@{color-@{value}-maxBtn}';
|
||||
}
|
||||
&.close {
|
||||
background-color: ~'@{color-@{value}-closeBtn}';
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,159 @@
|
||||
<template>
|
||||
<div :class="$style.menu">
|
||||
<ul :class="$style.list">
|
||||
<li v-for="item in menus" :key="item.to">
|
||||
<router-link :class="$style.link" :active-class="$style.active" :to="item.to" :tips="item.tips">
|
||||
<div :class="$style.icon">
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" :viewBox="item.iconSize" space="preserve">
|
||||
<use :xlink:href="item.icon"></use>
|
||||
</svg>
|
||||
</div>
|
||||
</router-link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
export default {
|
||||
name: 'Nav',
|
||||
computed: {
|
||||
...mapGetters(['setting']),
|
||||
menus() {
|
||||
return [
|
||||
{
|
||||
to: 'search',
|
||||
tips: this.$t('search'),
|
||||
icon: '#icon-search-2',
|
||||
iconSize: '0 0 425.2 425.2',
|
||||
enable: true,
|
||||
},
|
||||
{
|
||||
to: 'songList',
|
||||
tips: this.$t('song_list'),
|
||||
icon: '#icon-album',
|
||||
iconSize: '0 0 425.2 425.2',
|
||||
enable: true,
|
||||
},
|
||||
{
|
||||
to: 'leaderboard',
|
||||
tips: this.$t('leaderboard'),
|
||||
icon: '#icon-leaderboard',
|
||||
iconSize: '0 0 425.22 425.2',
|
||||
enable: true,
|
||||
},
|
||||
{
|
||||
to: 'list',
|
||||
tips: this.$t('my_list'),
|
||||
icon: '#icon-love',
|
||||
iconSize: '0 0 444.87 391.18',
|
||||
enable: true,
|
||||
},
|
||||
{
|
||||
to: 'download',
|
||||
tips: this.$t('download'),
|
||||
icon: '#icon-download-2',
|
||||
iconSize: '0 0 425.2 425.2',
|
||||
enable: this.setting.download.enable,
|
||||
},
|
||||
{
|
||||
to: 'setting',
|
||||
tips: this.$t('setting'),
|
||||
icon: '#icon-setting',
|
||||
iconSize: '0 0 493.23 436.47',
|
||||
enable: true,
|
||||
},
|
||||
].filter(m => m.enable)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" module>
|
||||
@import '@renderer/assets/styles/layout.less';
|
||||
|
||||
.menu {
|
||||
flex: auto;
|
||||
// &.controlBtnLeft {
|
||||
// display: flex;
|
||||
// flex-flow: column nowrap;
|
||||
// justify-content: center;
|
||||
// padding-bottom: @control-btn-height;
|
||||
// }
|
||||
// padding: 5px;
|
||||
}
|
||||
.list {
|
||||
-webkit-app-region: no-drag;
|
||||
// margin-bottom: 15px;
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
// dt {
|
||||
// padding-left: 5px;
|
||||
// font-size: 11px;
|
||||
// transition: @transition-theme;
|
||||
// transition-property: color;
|
||||
// color: @color-theme-font-label;
|
||||
// .mixin-ellipsis-1;
|
||||
// }
|
||||
}
|
||||
.link {
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
text-decoration: none;
|
||||
|
||||
position: relative;
|
||||
padding: 18px 3px;
|
||||
// margin: 5px 0;
|
||||
// border-left: 5px solid transparent;
|
||||
transition: @transition-theme;
|
||||
transition-property: color;
|
||||
color: @color-theme-font !important;
|
||||
cursor: pointer;
|
||||
font-size: 11.5px;
|
||||
text-align: center;
|
||||
outline: none;
|
||||
|
||||
transition: background-color 0.3s ease;
|
||||
// border-radius: @radius-border;
|
||||
.mixin-ellipsis-1;
|
||||
|
||||
&.active {
|
||||
// border-left-color: @color-theme-active;
|
||||
background-color: @color-theme-active;
|
||||
}
|
||||
|
||||
&:hover:not(.active) {
|
||||
background-color: @color-theme-hover;
|
||||
}
|
||||
&:hover:not(.active) {
|
||||
background-color: @color-theme-active;
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
// margin-bottom: 5px;
|
||||
&> svg {
|
||||
width: 32%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
each(@themes, {
|
||||
:global(#root.@{value}) {
|
||||
.link {
|
||||
color: ~'@{color-@{value}-theme-font}' !important;
|
||||
&.active {
|
||||
background-color: ~'@{color-@{value}-theme-active}';
|
||||
}
|
||||
&:hover:not(.active) {
|
||||
background-color: ~'@{color-@{value}-theme-hover}';
|
||||
}
|
||||
&:active:not(.active) {
|
||||
background-color: ~'@{color-@{value}-theme-active}';
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</style>
|
||||
@@ -0,0 +1,63 @@
|
||||
<template>
|
||||
<div :class="$style.aside">
|
||||
<ControlBtns v-if="setting.controlBtnPosition == 'left'" />
|
||||
<div :class="$style.logo" v-else>L X</div>
|
||||
<Nav />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
import ControlBtns from './ControlBtns'
|
||||
import Nav from './Nav'
|
||||
|
||||
export default {
|
||||
components: { ControlBtns, Nav },
|
||||
computed: {
|
||||
...mapGetters(['setting']),
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="less" module>
|
||||
@import '@renderer/assets/styles/layout.less';
|
||||
|
||||
.aside {
|
||||
// box-shadow: 0 0 5px rgba(0, 0, 0, .3);
|
||||
transition: @transition-theme;
|
||||
transition-property: background-color;
|
||||
background-color: @color-theme-sidebar;
|
||||
// background-color: @color-aside-background;
|
||||
// border-right: 2px solid @color-theme;
|
||||
-webkit-app-region: drag;
|
||||
-webkit-user-select: none;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
}
|
||||
|
||||
.logo {
|
||||
box-sizing: border-box;
|
||||
padding: 0 13%;
|
||||
height: 50px;
|
||||
color: @color-theme-font;
|
||||
flex: none;
|
||||
text-align: center;
|
||||
line-height: 50px;
|
||||
font-weight: bold;
|
||||
// -webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
each(@themes, {
|
||||
:global(#root.@{value}) {
|
||||
.aside {
|
||||
background-color: ~'@{color-@{value}-theme-sidebar}';
|
||||
}
|
||||
.logo {
|
||||
color: ~'@{color-@{value}-theme-font}';
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,163 @@
|
||||
<template lang="pug">
|
||||
div(:class="$style.container")
|
||||
ul
|
||||
li(v-for="(item, index) in comments" :key="item.id" :class="$style.listItem")
|
||||
div(:class="$style.content")
|
||||
div(:class="$style.left")
|
||||
img( :class="$style.avatar" :src="item.avatar || commentDefImg" @error="handleUserImg")
|
||||
div(:class="$style.right")
|
||||
div(:class="$style.info")
|
||||
div.select(:class="$style.name") {{item.userName}}
|
||||
time(:class="$style.time" v-if="item.timeStr") {{timeFormat(item.timeStr)}}
|
||||
div(:class="$style.likes" v-if="item.likedCount != null")
|
||||
svg(:class="$style.likesIcon" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' viewBox='0 0 512 512' space='preserve')
|
||||
use(xlink:href='#icon-thumbs-up')
|
||||
| {{item.likedCount}}
|
||||
div.select(:class="$style.comment_text")
|
||||
p(v-for="text in item.text") {{text}}
|
||||
comment-floor(v-if="item.reply && item.reply.length" :class="$style.reply_floor" :comments="item.reply")
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import commentDefImg from '@renderer/assets/images/defaultUser.jpg'
|
||||
|
||||
export default {
|
||||
name: 'commentFloor',
|
||||
props: {
|
||||
comments: {
|
||||
type: Array,
|
||||
default() {
|
||||
return []
|
||||
},
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
commentDefImg,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
timeFormat(time) {
|
||||
return time
|
||||
// return formatTime(new Date(time), true)
|
||||
},
|
||||
handleUserImg(event) {
|
||||
event.target.src = this.commentDefImg
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" module>
|
||||
@import '@renderer/assets/styles/layout.less';
|
||||
|
||||
@padding: 15px;
|
||||
|
||||
.container {
|
||||
|
||||
}
|
||||
|
||||
.listItem {
|
||||
border-bottom: 1px dashed @color-theme_2-line;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 12px 0;
|
||||
font-size: 13px;
|
||||
color: @color-theme_2-font;
|
||||
display: flex;
|
||||
}
|
||||
.left {
|
||||
flex: none;
|
||||
}
|
||||
.avatar {
|
||||
width: 40px;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 2px rgba(0, 0, 0, .15);
|
||||
}
|
||||
.right {
|
||||
flex: auto;
|
||||
min-width: 0;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
align-items: flex-end;
|
||||
min-width: 0;
|
||||
line-height: 1.3;
|
||||
color: @color-theme_2-font-label;
|
||||
}
|
||||
.name {
|
||||
flex: 0 1 auto;
|
||||
min-width: 0;
|
||||
.mixin-ellipsis-1;
|
||||
}
|
||||
.time {
|
||||
flex: none;
|
||||
font-size: 11px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
.likes {
|
||||
flex: 1 0 auto;
|
||||
margin-left: 10px;
|
||||
font-size: 11px;
|
||||
align-self: flex-end;
|
||||
text-align: right;
|
||||
}
|
||||
.likesIcon {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
margin-right: 3px;
|
||||
color: @color-theme-active;
|
||||
}
|
||||
.comment_text {
|
||||
text-align: justify;
|
||||
font-size: 14px;
|
||||
padding-top: 5px;
|
||||
p {
|
||||
line-height: 1.5;
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
|
||||
.reply_floor {
|
||||
padding: 0 0 0 @padding;
|
||||
margin-left: @padding * 2;
|
||||
border-radius: .5rem;
|
||||
&:last-child {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.listItem:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
.right {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
background-color: @color-reply-floor;
|
||||
}
|
||||
|
||||
|
||||
each(@themes, {
|
||||
:global(#root.@{value}) {
|
||||
.listItem {
|
||||
border-bottom-color: ~'@{color-@{value}-theme_2-active}';
|
||||
}
|
||||
.content {
|
||||
color: ~'@{color-@{value}-theme_2-font}';
|
||||
}
|
||||
.info {
|
||||
color: ~'@{color-@{value}-theme_2-font-label}';
|
||||
}
|
||||
.likesIcon {
|
||||
color: ~'@{color-@{value}-theme-active}';
|
||||
}
|
||||
.reply_floor {
|
||||
background-color: ~'@{color-@{value}-reply-floor}';
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,274 @@
|
||||
<template lang="pug">
|
||||
div.comment(:class="$style.comment")
|
||||
div(:class="$style.commentHeader")
|
||||
h3 {{$t('comment__title', { name: title })}}
|
||||
div(:class="$style.commentHeaderBtns")
|
||||
div(:class="$style.commentHeaderBtn" @click="handleShowComment" :tips="$t('comment__refresh')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' style='transform: rotate(45deg);' viewBox='0 0 24 24' space='preserve')
|
||||
use(xlink:href='#icon-refresh')
|
||||
div(:class="$style.commentHeaderBtn" @click="$emit('close')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' viewBox='0 0 24 24' space='preserve')
|
||||
use(xlink:href='#icon-close')
|
||||
|
||||
div.scroll(:class="$style.commentMain" ref="dom_comment")
|
||||
div(v-if="page == 1")
|
||||
h2(:class="$style.commentType") {{$t('comment__hot_title')}}
|
||||
p(:class="$style.commentLabel" style="cursor: pointer;" v-if="isHotLoadError" @click="handleGetHotComment(currentMusicInfo)") {{$t('comment__hot_load_error')}}
|
||||
p(:class="$style.commentLabel" v-else-if="isHotLoading && !hotComments.length") {{$t('comment__hot_loading')}}
|
||||
comment-floor(v-if="!isHotLoadError && hotComments.length" :class="[$style.commentFloor, isHotLoading ? $style.loading : null]" :comments="hotComments")
|
||||
p(:class="$style.commentLabel" v-else-if="!isHotLoadError && !isHotLoading") {{$t('comment__no_content')}}
|
||||
div
|
||||
h2(:class="$style.commentType") {{$t('comment__new_title')}} ({{total}})
|
||||
p(:class="$style.commentLabel" style="cursor: pointer;" v-if="isNewLoadError" @click="handleGetNewComment(currentMusicInfo, nextPage, limit)") {{$t('comment__new_load_error')}}
|
||||
p(:class="$style.commentLabel" v-else-if="isNewLoading && !newComments.length") {{$t('comment__new_loading')}}
|
||||
comment-floor(v-if="!isNewLoadError && newComments.length" :class="[$style.commentFloor, isNewLoading ? $style.loading : null]" :comments="newComments")
|
||||
p(:class="$style.commentLabel" v-else-if="!isNewLoadError && !isNewLoading") {{$t('comment__no_content')}}
|
||||
div(:class="$style.pagination")
|
||||
material-pagination(:count="total" :btnLength="5" :limit="limit" :page="page" @btn-click="handleToggleCommentPage")
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import { scrollTo } from '@renderer/utils'
|
||||
import music from '@renderer/utils/music'
|
||||
import CommentFloor from './CommentFloor'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
musicInfo: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
components: {
|
||||
CommentFloor,
|
||||
},
|
||||
emits: ['close'],
|
||||
data() {
|
||||
return {
|
||||
currentMusicInfo: {
|
||||
name: '',
|
||||
singer: '',
|
||||
},
|
||||
page: 1,
|
||||
total: 0,
|
||||
maxPage: 1,
|
||||
limit: 20,
|
||||
isHotLoading: true,
|
||||
isNewLoading: false,
|
||||
isHotLoadError: true,
|
||||
isNewLoadError: false,
|
||||
nextPage: 1,
|
||||
newComments: [
|
||||
// {
|
||||
// text: ['123123hhh'],
|
||||
// userName: 'dsads',
|
||||
// avatar: 'http://img4.kuwo.cn/star/userhead/39/52/1602393411654_512039239s.jpg',
|
||||
// time: '2020-10-22 22:14:17',
|
||||
// timeStr: '2020-10-22 22:14:17',
|
||||
// likedCount: 100,
|
||||
// reply: [],
|
||||
// },
|
||||
],
|
||||
hotComments: [
|
||||
// {
|
||||
// text: ['123123hhh'],
|
||||
// userName: 'dsads',
|
||||
// avatar: 'http://img4.kuwo.cn/star/userhead/39/52/1602393411654_512039239s.jpg',
|
||||
// time: '2020-10-22 22:14:17',
|
||||
// timeStr: '2020-10-22 22:14:17',
|
||||
// likedCount: 100,
|
||||
// reply: [
|
||||
// {
|
||||
// text: ['123123hhh'],
|
||||
// userName: 'dsads',
|
||||
// avatar: 'http://img4.kuwo.cn/star/userhead/39/52/1602393411654_512039239s.jpg',
|
||||
// time: '2020-10-22 22:14:17',
|
||||
// timeStr: '2020-10-22 22:14:17',
|
||||
// likedCount: 100,
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['setting']),
|
||||
title() {
|
||||
return this.currentMusicInfo.name
|
||||
? this.setting.download.fileName.replace('歌名', this.currentMusicInfo.name).replace('歌手', this.currentMusicInfo.singer)
|
||||
: '^-^'
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
show(n) {
|
||||
if (n) this.handleShowComment()
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async getComment(musicInfo, page, limit, retryNum = 0) {
|
||||
let resp
|
||||
try {
|
||||
resp = await music[musicInfo.source].comment.getComment(musicInfo, page, limit)
|
||||
} catch (error) {
|
||||
if (error.message == '取消请求' || ++retryNum > 2) throw error
|
||||
resp = await this.getComment(musicInfo, page, limit, retryNum)
|
||||
}
|
||||
return resp
|
||||
},
|
||||
async getHotComment(musicInfo, retryNum = 0) {
|
||||
let resp
|
||||
try {
|
||||
resp = await music[musicInfo.source].comment.getHotComment(musicInfo)
|
||||
} catch (error) {
|
||||
if (error.message == '取消请求' || ++retryNum > 2) throw error
|
||||
resp = await this.getHotComment(musicInfo, retryNum)
|
||||
}
|
||||
return resp
|
||||
},
|
||||
handleGetNewComment(musicInfo, page, limit) {
|
||||
this.isNewLoadError = false
|
||||
this.isNewLoading = true
|
||||
this.getComment(musicInfo, page, limit).then(comment => {
|
||||
this.isNewLoading = false
|
||||
this.total = comment.total
|
||||
this.maxPage = comment.maxPage
|
||||
this.page = page
|
||||
this.newComments = comment.comments
|
||||
this.$nextTick(() => {
|
||||
scrollTo(this.$refs.dom_comment, 0, 300)
|
||||
})
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
if (err.message == '取消请求') return
|
||||
this.isNewLoadError = true
|
||||
this.isNewLoading = false
|
||||
})
|
||||
},
|
||||
handleGetHotComment(musicInfo) {
|
||||
this.isHotLoadError = false
|
||||
this.isHotLoading = true
|
||||
this.getHotComment(musicInfo).then(hotComment => {
|
||||
this.isHotLoading = false
|
||||
this.hotComments = hotComment.comments
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
if (err.message == '取消请求') return
|
||||
this.isHotLoadError = true
|
||||
this.isHotLoading = false
|
||||
})
|
||||
},
|
||||
handleShowComment() {
|
||||
if (!this.musicInfo.songmid || !music[this.musicInfo.source].comment) return
|
||||
// if (this.musicInfo.songmid != this.currentMusicInfo.songmid) {
|
||||
this.page = 1
|
||||
this.total = 0
|
||||
this.maxPage = 1
|
||||
this.nextPage = 1
|
||||
// }
|
||||
this.isShowComment = true
|
||||
this.currentMusicInfo = this.musicInfo
|
||||
|
||||
if (this.page == 1) this.handleGetHotComment(this.currentMusicInfo)
|
||||
this.handleGetNewComment(this.currentMusicInfo, this.page, this.limit)
|
||||
},
|
||||
handleToggleCommentPage(page) {
|
||||
this.nextPage = page
|
||||
this.handleGetNewComment(this.currentMusicInfo, page, this.limit)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" module>
|
||||
@import '@renderer/assets/styles/layout.less';
|
||||
|
||||
.comment {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
transition: @transition-theme;
|
||||
transition-property: transform,opacity;
|
||||
transform-origin: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
.commentHeader {
|
||||
flex: none;
|
||||
padding-bottom: 5px;
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
align-items: center;
|
||||
// border-bottom: 1px solid #eee;
|
||||
h3 {
|
||||
font-size: 14px;
|
||||
.mixin-ellipsis-1;
|
||||
line-height: 1.2;
|
||||
}
|
||||
}
|
||||
.commentHeaderBtns {
|
||||
flex: 1 0 auto;
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
justify-content: flex-end;
|
||||
color: @color-theme;
|
||||
}
|
||||
.commentHeaderBtn {
|
||||
height: 22px;
|
||||
width: 22px;
|
||||
cursor: pointer;
|
||||
transition: opacity @transition-theme;
|
||||
|
||||
+.commentHeaderBtn {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
opacity: .7;
|
||||
}
|
||||
}
|
||||
.commentMain {
|
||||
flex: auto;
|
||||
padding-left: 15px;
|
||||
padding-right: 10px;
|
||||
background-color: @color-reply-floor;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.commentLabel {
|
||||
padding: 15px;
|
||||
color: @color-theme_2-font-label;
|
||||
font-size: 14px;
|
||||
}
|
||||
.commentType {
|
||||
padding: 10px 0;
|
||||
font-size: 13px;
|
||||
color: @color-theme;
|
||||
}
|
||||
.commentFloor {
|
||||
opacity: 1;
|
||||
transition: opacity @transition-theme;
|
||||
|
||||
&.loading {
|
||||
opacity: .4;
|
||||
}
|
||||
}
|
||||
.pagination {
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
each(@themes, {
|
||||
:global(#root.@{value}) {
|
||||
.commentHeaderBtns {
|
||||
color: ~'@{color-@{value}-theme}';
|
||||
}
|
||||
.commentMain {
|
||||
background-color: ~'@{color-@{value}-reply-floor}';
|
||||
}
|
||||
.commentLabel {
|
||||
color: ~'@{color-@{value}-theme_2-font-label}';
|
||||
}
|
||||
.commentType {
|
||||
color: ~'@{color-@{value}-theme}';
|
||||
}
|
||||
}
|
||||
})
|
||||
</style>
|
||||
@@ -0,0 +1,186 @@
|
||||
<template lang="pug">
|
||||
material-modal(:show="!setting.isAgreePact || isShowPact" @close="handleClose(false)" :bgClose="setting.isAgreePact" :close-btn="setting.isAgreePact")
|
||||
main(:class="$style.main")
|
||||
h2 许可协议
|
||||
div.select.scroll(:class="$style.content")
|
||||
p
|
||||
| 本项目(软件)基于
|
||||
strong.hover.underline(@click="openUrl('http://www.apache.org/licenses/LICENSE-2.0')") Apache License 2.0
|
||||
| 许可证发行,在使用本软件前,你(使用者)需签署本协议才可继续使用,以下协议是对于 Apache License 2.0 的补充,如有冲突,以以下协议为准。
|
||||
br
|
||||
p 词语约定:本协议中的“本软件”指洛雪音乐桌面版项目;“使用者”指签署本协议的使用者;“官方音乐平台”指对本软件内置的包括酷我、酷狗、咪咕等音乐源的官方平台统称;“版权数据”指包括但不限于图像、音频、名字等在内的他人拥有所属版权的数据。
|
||||
br
|
||||
p
|
||||
strong 1、
|
||||
| 本软件的数据来源原理是从各官方音乐平台的公开服务器中拉取数据,经过对数据简单地筛选与合并后进行展示,因此本软件不对数据的准确性负责。
|
||||
p
|
||||
strong 2、
|
||||
| 使用本软件的过程中可能会产生版权数据,对于这些版权数据,本软件不拥有它们的所有权,为了避免造成侵权,使用者务必在
|
||||
strong 24小时内
|
||||
| 清除使用本软件的过程中所产生的版权数据。
|
||||
p
|
||||
strong 3、
|
||||
| 本软件内的官方音乐平台别名为本软件内对官方音乐平台的一个称呼,不包含恶意,如果官方音乐平台觉得不妥,可联系本软件更改或移除。
|
||||
p
|
||||
strong 4、
|
||||
| 本软件内使用的部分包括但不限于字体、图片等资源来源于互联网,如果出现侵权可联系本软件移除。
|
||||
p
|
||||
strong 5、
|
||||
| 由于使用本软件产生的包括由于本协议或由于使用或无法使用本软件而引起的任何性质的任何直接、间接、特殊、偶然或结果性损害(包括但不限于因商誉损失、停工、计算机故障或故障引起的损害赔偿,或任何及所有其他商业损害或损失)由使用者负责。
|
||||
p
|
||||
strong 6、
|
||||
| 本项目完全免费,且开源发布于
|
||||
span.hover.underline(@click="openUrl('https://github.com/lyswhut/lx-music-desktop#readme')") GitHub
|
||||
| 面向全世界人用作对技术的学习交流,本软件不对项目内的技术可能存在违反当地法律法规的行为作保证,
|
||||
strong 禁止在违反当地法律法规的情况下使用本软件
|
||||
|,对于使用者在明知或不知当地法律法规不允许的情况下使用本软件所造成的任何违法违规行为由使用者承担,本软件不承担由此造成的任何直接、间接、特殊、偶然或结果性责任。
|
||||
br
|
||||
p
|
||||
strong *
|
||||
| 若协议更新,恕不另行通知,可到开源地址查看。
|
||||
p
|
||||
strong *
|
||||
| 本软件的初衷是帮助官方音乐平台简化数据后代为展示,帮助使用者根据歌曲名、艺术家等关键字快速地定位所需内容所在的音乐平台。
|
||||
p
|
||||
strong *
|
||||
| 音乐平台不易,建议到对应音乐平台支持正版资源。
|
||||
|
||||
br
|
||||
p(v-if="!setting.isAgreePact")
|
||||
strong 若你(使用者)接受以上协议,请点击下面的“接受”按钮签署本协议,若不接受,请点击“不接受”后退出软件并清除本软件的所有数据。
|
||||
|
||||
|
||||
div(:class="$style.btns" v-if="!setting.isAgreePact")
|
||||
base-btn(:class="$style.btn" @click="handleClose(true)") {{$t('not_agree')}}
|
||||
base-btn(:class="$style.btn" :disabled="!btnEnable" @click="handleClick()") {{$t('agree')}} {{timeStr}}
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapMutations } from 'vuex'
|
||||
import { rendererSend, NAMES } from '@common/ipc'
|
||||
import { openUrl } from '@renderer/utils'
|
||||
import { isShowPact } from '@renderer/core/share'
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
return {
|
||||
isShowPact,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
time: 20,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['setting']),
|
||||
btnEnable() {
|
||||
return this.time == 0
|
||||
},
|
||||
timeStr() {
|
||||
return this.btnEnable ? '' : `(${this.time})`
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
'setting.isAgreePact'(n) {
|
||||
if (n) return
|
||||
this.time = 5
|
||||
this.startTimeout()
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
if (!this.setting.isAgreePact) {
|
||||
this.startTimeout()
|
||||
}
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['setAgreePact']),
|
||||
handleClick() {
|
||||
this.setAgreePact()
|
||||
setTimeout(() => {
|
||||
this.$dialog({
|
||||
message: Buffer.from('e69cace8bdafe4bbb6e5ae8ce585a8e5858de8b4b9e4b894e5bc80e6ba90efbc8ce5a682e69e9ce4bda0e698afe88ab1e992b1e8b4ade4b9b0e79a84efbc8ce8afb7e79bb4e68ea5e7bb99e5b7aee8af84efbc810a0a5468697320736f667477617265206973206672656520616e64206f70656e20736f757263652e', 'hex').toString(),
|
||||
confirmButtonText: Buffer.from('e5a5bde79a8420284f4b29', 'hex').toString(),
|
||||
})
|
||||
}, 2000)
|
||||
},
|
||||
handleClose(isExit) {
|
||||
if (isExit) return rendererSend(NAMES.mainWindow.close, true)
|
||||
isShowPact.value = false
|
||||
},
|
||||
openUrl(url) {
|
||||
openUrl(url)
|
||||
},
|
||||
startTimeout() {
|
||||
setTimeout(() => {
|
||||
if (--this.time > 0) this.startTimeout()
|
||||
}, 1000)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="less" module>
|
||||
@import '@renderer/assets/styles/layout.less';
|
||||
|
||||
.main {
|
||||
padding: 15px;
|
||||
max-width: 550px;
|
||||
min-width: 200px;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
justify-content: center;
|
||||
h2 {
|
||||
font-size: 16px;
|
||||
color: @color-theme_2-font;
|
||||
line-height: 1.3;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: auto;
|
||||
margin: 15px 0;
|
||||
padding-right: 5px;
|
||||
h3 {
|
||||
font-weight: bold;
|
||||
line-height: 2;
|
||||
}
|
||||
p {
|
||||
line-height: 1.5;
|
||||
font-size: 14px;
|
||||
text-align: justify;
|
||||
}
|
||||
}
|
||||
|
||||
.btns {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.btn {
|
||||
display: block;
|
||||
width: 48%;
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
each(@themes, {
|
||||
:global(#root.@{value}) {
|
||||
.main {
|
||||
h2 {
|
||||
color: ~'@{color-@{value}-theme_2-font}';
|
||||
}
|
||||
}
|
||||
.name {
|
||||
color: ~'@{color-@{value}-theme}';
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,131 @@
|
||||
<template>
|
||||
<div :class="$style.controlBtn">
|
||||
<common-volume-bar :setting="setting" />
|
||||
<div :class="$style.titleBtn" @click="toggleDesktopLyric" @contextmenu="toggleLockDesktopLyric" :tips="toggleDesktopLyricBtnTitle">
|
||||
<svg v-if="setting.desktopLyric.enable" version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" height="100%" viewBox="0 0 512 512" space="preserve">
|
||||
<use xlink:href="#icon-desktop-lyric-on"></use>
|
||||
</svg>
|
||||
<svg v-else version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" height="100%" viewBox="0 0 512 512" space="preserve">
|
||||
<use xlink:href="#icon-desktop-lyric-off"></use>
|
||||
</svg>
|
||||
</div>
|
||||
<div :class="$style.titleBtn" @click="toggleNextPlayMode" :tips="nextTogglePlayName">
|
||||
<svg v-if="setting.player.togglePlayMethod == 'listLoop'" version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" height="80%" viewBox="0 0 24 24" space="preserve">
|
||||
<use xlink:href="#icon-list-loop"></use>
|
||||
</svg>
|
||||
<svg v-else-if="setting.player.togglePlayMethod == 'random'" version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" width="100%" viewBox="0 0 24 24" space="preserve">
|
||||
<use xlink:href="#icon-list-random"></use>
|
||||
</svg>
|
||||
<svg v-else-if="setting.player.togglePlayMethod == 'list'" version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" width="120%" viewBox="0 0 24 24" space="preserve">
|
||||
<use xlink:href="#icon-list-order"></use>
|
||||
</svg>
|
||||
<svg v-else-if="setting.player.togglePlayMethod == 'singleLoop'" version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" width="100%" viewBox="0 0 24 24" space="preserve">
|
||||
<use xlink:href="#icon-single-loop"></use>
|
||||
</svg>
|
||||
<svg v-else version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" width="120%" viewBox="0 0 24 24" space="preserve">
|
||||
<use xlink:href="#icon-single"></use>
|
||||
</svg>
|
||||
</div>
|
||||
<div :class="$style.titleBtn" @click="addMusicTo" :tips="$t('player__add_music_to')">
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" height="80%" viewBox="0 0 512 512" space="preserve">
|
||||
<use xlink:href="#icon-add-2"></use>
|
||||
</svg>
|
||||
</div>
|
||||
<teleport to="#root">
|
||||
<common-list-add-modal :show="isShowAddMusicTo" :musicInfo="musicInfoItem" @close="isShowAddMusicTo = false" />
|
||||
</teleport>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useI18n, ref, useRefGetter } from '@renderer/utils/vueTools'
|
||||
import useNextTogglePlay from '@renderer/utils/compositions/useNextTogglePlay'
|
||||
import useToggleDesktopLyric from '@renderer/utils/compositions/useToggleDesktopLyric'
|
||||
import { musicInfo, musicInfoItem } from '@renderer/core/share/player'
|
||||
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const { t } = useI18n()
|
||||
const isShowAddMusicTo = ref(false)
|
||||
|
||||
const setting = useRefGetter('setting')
|
||||
|
||||
|
||||
const {
|
||||
nextTogglePlayName,
|
||||
toggleNextPlayMode,
|
||||
} = useNextTogglePlay({ setting, t })
|
||||
|
||||
const {
|
||||
toggleDesktopLyricBtnTitle,
|
||||
toggleDesktopLyric,
|
||||
toggleLockDesktopLyric,
|
||||
} = useToggleDesktopLyric({ setting, t })
|
||||
|
||||
|
||||
const addMusicTo = () => {
|
||||
if (!musicInfo.songmid) return
|
||||
isShowAddMusicTo.value = true
|
||||
}
|
||||
|
||||
return {
|
||||
setting: setting,
|
||||
isShowAddMusicTo,
|
||||
nextTogglePlayName,
|
||||
toggleNextPlayMode,
|
||||
toggleDesktopLyricBtnTitle,
|
||||
toggleDesktopLyric,
|
||||
toggleLockDesktopLyric,
|
||||
addMusicTo,
|
||||
musicInfoItem,
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" module>
|
||||
@import '@renderer/assets/styles/layout.less';
|
||||
|
||||
.controlBtn {
|
||||
flex: none;
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
}
|
||||
|
||||
.titleBtn {
|
||||
flex: none;
|
||||
margin-left: 5px;
|
||||
height: 100%;
|
||||
width: 20px;
|
||||
color: @color-btn;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
transition: opacity 0.2s ease;
|
||||
opacity: .6;
|
||||
cursor: pointer;
|
||||
|
||||
svg {
|
||||
filter: drop-shadow(0 0 1px rgba(0, 0, 0, 0.2));
|
||||
}
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
&:active {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
each(@themes, {
|
||||
:global(#root.@{value}) {
|
||||
.titleBtn {
|
||||
color: ~'@{color-@{value}-btn}';
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,361 @@
|
||||
<template lang="pug">
|
||||
div(:class="$style.player")
|
||||
div(:class="$style.left" @contextmenu="handleToMusicLocation" @click="showPlayerDetail" :tips="$t('player__pic_tip')")
|
||||
img(v-if="musicInfo.img" :src="musicInfo.img" @error="imgError")
|
||||
svg(v-else version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='102%' width='100%' viewBox='0 0 60 60' space='preserve')
|
||||
use(:xlink:href='`#${$style.iconPic}`')
|
||||
div(:class="$style.middle")
|
||||
div(:class="$style.column1")
|
||||
div(:class="$style.container")
|
||||
div(:class="$style.title" @click="handleCopy(title)" :tips="title + $t('copy_tip')") {{title}}
|
||||
control-btns
|
||||
div(:class="$style.column2")
|
||||
common-progress-bar(:progress="progress" :handleTransitionEnd="handleTransitionEnd" :isActiveTransition="isActiveTransition")
|
||||
div(:class="$style.column3")
|
||||
span(:class="$style.statusText") {{statusText}}
|
||||
span {{nowPlayTimeStr}}
|
||||
span(style="margin: 0 5px;") /
|
||||
span {{maxPlayTimeStr}}
|
||||
div(:class="$style.right")
|
||||
div(:class="$style.playBtn" @click='playPrev' :tips="$t('player__prev')" style="transform: rotate(180deg);")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 220.847 220.847' space='preserve')
|
||||
use(xlink:href='#icon-nextMusic')
|
||||
div(:class="$style.playBtn" :tips="isPlay ? $t('player__pause') : $t('player__play')" @click='togglePlay')
|
||||
svg(v-if="isPlay" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 277.338 277.338' space='preserve')
|
||||
use(xlink:href='#icon-pause')
|
||||
svg(v-else version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 170 170' space='preserve')
|
||||
use(xlink:href='#icon-play')
|
||||
div(:class="$style.playBtn" @click='playNext' :tips="$t('player__next')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 220.847 220.847' space='preserve')
|
||||
use(xlink:href='#icon-nextMusic')
|
||||
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' style="display: none;")
|
||||
g(:id="$style.iconPic")
|
||||
path(d='M29,0C12.984,0,0,12.984,0,29c0,16.016,12.984,29,29,29s29-12.984,29-29C58,12.984,45.016,0,29,0zM29,36.08c-3.91,0-7.08-3.17-7.08-7.08c0-3.91,3.17-7.08,7.08-7.08s7.08,3.17,7.08,7.08C36.08,32.91,32.91,36.08,29,36.08z')
|
||||
path(:class="$style.c1" d='M6.487,22.932c-0.077,0-0.156-0.009-0.234-0.027c-0.537-0.13-0.868-0.67-0.739-1.206c0.946-3.935,2.955-7.522,5.809-10.376s6.441-4.862,10.376-5.809c0.536-0.127,1.077,0.202,1.206,0.739c0.129,0.536-0.202,1.076-0.739,1.206c-3.575,0.859-6.836,2.685-9.429,5.277s-4.418,5.854-5.277,9.429C7.349,22.624,6.938,22.932,6.487,22.932z')
|
||||
path(:class="$style.c1" d='M36.066,52.514c-0.451,0-0.861-0.308-0.972-0.767c-0.129-0.536,0.202-1.076,0.739-1.206c3.576-0.859,6.837-2.685,9.43-5.277s4.418-5.854,5.277-9.429c0.129-0.538,0.668-0.868,1.206-0.739c0.537,0.13,0.868,0.67,0.739,1.206c-0.946,3.935-2.955,7.522-5.809,10.376s-6.441,4.862-10.377,5.809C36.223,52.505,36.144,52.514,36.066,52.514z')
|
||||
path(:class="$style.c1" d='M11.313,24.226c-0.075,0-0.151-0.008-0.228-0.026c-0.538-0.125-0.873-0.663-0.747-1.2c0.72-3.09,2.282-5.904,4.52-8.141c2.236-2.237,5.051-3.8,8.141-4.52c0.535-0.131,1.075,0.209,1.2,0.747c0.126,0.537-0.209,1.075-0.747,1.2c-2.725,0.635-5.207,2.014-7.18,3.986s-3.352,4.455-3.986,7.18C12.179,23.914,11.768,24.226,11.313,24.226z')
|
||||
path(:class="$style.c1" d='M34.773,47.688c-0.454,0-0.865-0.312-0.973-0.773c-0.126-0.537,0.209-1.075,0.747-1.2c2.725-0.635,5.207-2.014,7.18-3.986s3.352-4.455,3.986-7.18c0.125-0.538,0.662-0.88,1.2-0.747c0.538,0.125,0.873,0.663,0.747,1.2c-0.72,3.09-2.282,5.904-4.52,8.141c-2.236,2.237-5.051,3.8-8.141,4.52C34.925,47.68,34.849,47.688,34.773,47.688z')
|
||||
path(:class="$style.c1" d='M16.14,25.519c-0.071,0-0.143-0.008-0.215-0.023c-0.539-0.118-0.881-0.651-0.763-1.19c0.997-4.557,4.586-8.146,9.143-9.143c0.537-0.116,1.071,0.222,1.19,0.763c0.118,0.539-0.224,1.072-0.763,1.19c-3.796,0.831-6.786,3.821-7.617,7.617C17.013,25.2,16.6,25.519,16.14,25.519z')
|
||||
path(:class="$style.c1" d='M33.48,42.861c-0.46,0-0.873-0.318-0.976-0.786c-0.118-0.539,0.224-1.072,0.763-1.19c3.796-0.831,6.786-3.821,7.617-7.617c0.118-0.541,0.65-0.881,1.19-0.763c0.539,0.118,0.881,0.651,0.763,1.19c-0.997,4.557-4.586,8.146-9.143,9.143C33.623,42.854,33.552,42.861,33.48,42.861z')
|
||||
path(:class="$style.c2" d='M29,38.08c-5.007,0-9.08-4.073-9.08-9.08s4.073-9.08,9.08-9.08s9.08,4.073,9.08,9.08S34.007,38.08,29,38.08z M29,23.92c-2.801,0-5.08,2.279-5.08,5.08s2.279,5.08,5.08,5.08s5.08-2.279,5.08-5.08S31.801,23.92,29,23.92z')
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useRefGetter, computed, useRouter } from '@renderer/utils/vueTools'
|
||||
import { clipboardWriteText } from '@renderer/utils'
|
||||
import { player as eventPlayerNames } from '@renderer/event/names'
|
||||
import ControlBtns from './ControlBtns'
|
||||
import usePlayProgress from '@renderer/utils/compositions/usePlayProgress'
|
||||
// import { lyric } from '@renderer/core/share/lyric'
|
||||
import { statusText, musicInfo, setShowPlayerDetail, isPlay, musicInfoItem, playInfo, playMusicInfo } from '@renderer/core/share/player'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ControlBtns,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isShowAddMusicTo: false,
|
||||
}
|
||||
},
|
||||
setup() {
|
||||
const setting = useRefGetter('setting')
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const {
|
||||
nowPlayTimeStr,
|
||||
maxPlayTimeStr,
|
||||
progress,
|
||||
isActiveTransition,
|
||||
handleTransitionEnd,
|
||||
} = usePlayProgress()
|
||||
|
||||
const showPlayerDetail = () => {
|
||||
if (!musicInfoItem.value.songmid) return
|
||||
setShowPlayerDetail(true)
|
||||
}
|
||||
const handleCopy = (text) => {
|
||||
clipboardWriteText(text)
|
||||
}
|
||||
|
||||
const imgError = () => {
|
||||
// console.log(e)
|
||||
// musicInfo.img = null
|
||||
}
|
||||
|
||||
const handleToMusicLocation = () => {
|
||||
const listId = playMusicInfo.listId
|
||||
if (!listId || listId == '__temp__' || listId == 'download' || !musicInfoItem.value.songmid) return
|
||||
if (playInfo.playIndex == -1) return
|
||||
router.push({
|
||||
path: 'list',
|
||||
query: {
|
||||
id: listId,
|
||||
scrollIndex: playInfo.playIndex,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const title = computed(() => {
|
||||
return musicInfo.name
|
||||
? setting.value.download.fileName.replace('歌名', musicInfo.name).replace('歌手', musicInfo.singer)
|
||||
: '^-^'
|
||||
})
|
||||
|
||||
|
||||
const togglePlay = () => {
|
||||
window.eventHub.emit(eventPlayerNames.setTogglePlay)
|
||||
}
|
||||
const playNext = () => {
|
||||
window.eventHub.emit(eventPlayerNames.setPlayNext)
|
||||
}
|
||||
const playPrev = () => {
|
||||
window.eventHub.emit(eventPlayerNames.setPlayPrev)
|
||||
}
|
||||
|
||||
// onBeforeUnmount(() => {
|
||||
// window.eventHub.emit(eventPlayerNames.setTogglePlay)
|
||||
// })
|
||||
|
||||
return {
|
||||
musicInfo,
|
||||
nowPlayTimeStr,
|
||||
maxPlayTimeStr,
|
||||
progress,
|
||||
isActiveTransition,
|
||||
handleTransitionEnd,
|
||||
handleCopy,
|
||||
imgError,
|
||||
statusText,
|
||||
title,
|
||||
showPlayerDetail,
|
||||
isPlay,
|
||||
togglePlay,
|
||||
setting,
|
||||
playNext,
|
||||
playPrev,
|
||||
handleToMusicLocation,
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="less" module>
|
||||
@import '@renderer/assets/styles/layout.less';
|
||||
|
||||
.player {
|
||||
height: @height-player;
|
||||
background-color: @color-theme_2;
|
||||
transition: @transition-theme;
|
||||
transition-property: border-color;
|
||||
border-top: 2px solid @color-theme;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
z-index: 2;
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
.left {
|
||||
width: @height-player - 2;
|
||||
height: 100%;
|
||||
color: @color-theme;
|
||||
transition: @transition-theme;
|
||||
transition-property: color;
|
||||
flex: none;
|
||||
padding: 2PX;
|
||||
opacity: 1;
|
||||
transition: @transition-theme;
|
||||
transition-property: opacity;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
// align-items: center;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
opacity: .8;
|
||||
}
|
||||
|
||||
svg {
|
||||
fill: currentColor;
|
||||
}
|
||||
img {
|
||||
box-shadow: 0 0 2px rgba(0, 0, 0, 0.3);
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
transition: @transition-theme;
|
||||
transition-property: border-color;
|
||||
// border-radius: 50%;
|
||||
border-radius: @radius-border;
|
||||
// border: 2px solid @color-theme_2-background_1;
|
||||
}
|
||||
}
|
||||
.middle {
|
||||
flex: auto;
|
||||
height: 100%;
|
||||
padding: 5px 10px 5px 8px;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
}
|
||||
.right {
|
||||
height: 100%;
|
||||
flex: none;
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
align-items: center;
|
||||
padding-left: 15px;
|
||||
padding-right: 20px;
|
||||
}
|
||||
.column1 {
|
||||
flex: auto;
|
||||
position: relative;
|
||||
font-size: 16px;
|
||||
.container {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
flex: 0 1 auto;
|
||||
min-width: 0;
|
||||
padding-right: 5px;
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
.mixin-ellipsis-1;
|
||||
}
|
||||
|
||||
.play-btn {
|
||||
+ .play-btn {
|
||||
margin-left: 15px;
|
||||
}
|
||||
flex: none;
|
||||
height: 46%;
|
||||
// margin-top: -2px;
|
||||
// transition: @transition-theme;
|
||||
// transition-property: color;
|
||||
// color: @color-theme;
|
||||
transition: opacity 0.2s ease;
|
||||
opacity: 1;
|
||||
cursor: pointer;
|
||||
|
||||
svg {
|
||||
fill: currentColor;
|
||||
filter: drop-shadow(0 0 1px rgba(0, 0, 0, 0.2));
|
||||
}
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
&:active {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
.column2 {
|
||||
flex: none;
|
||||
padding: 3px 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
||||
.column3 {
|
||||
transition: @transition-theme;
|
||||
transition-property: color;
|
||||
color: @color-theme_2-font;
|
||||
flex: none;
|
||||
font-size: 12px;
|
||||
display: flex;
|
||||
padding-top: 2px;
|
||||
// justify-content: space-between;
|
||||
height: 16px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.status-text {
|
||||
font-size: 0.98em;
|
||||
transition: @transition-theme;
|
||||
transition-property: color;
|
||||
color: @color-player-status-text;
|
||||
.mixin-ellipsis-1;
|
||||
// padding: 0 5px;
|
||||
padding-right: 5px;
|
||||
flex: 1 1 0;
|
||||
// text-align: center;
|
||||
line-height: 1.2;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
#icon-pic {
|
||||
color: @color-theme;
|
||||
.c1 {
|
||||
transition: @transition-theme;
|
||||
transition-property: fill;
|
||||
fill: @color-player-pic-c1;
|
||||
}
|
||||
.c2 {
|
||||
transition: @transition-theme;
|
||||
transition-property: fill;
|
||||
fill: @color-player-pic-c2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
each(@themes, {
|
||||
:global(#root.@{value}) {
|
||||
.player {
|
||||
background-color: ~'@{color-@{value}-theme_2}';
|
||||
border-top-color: ~'@{color-@{value}-theme}';
|
||||
}
|
||||
.left {
|
||||
color: ~'@{color-@{value}-theme}';
|
||||
// img {
|
||||
// border-color: ~'@{color-@{value}-theme_2-background_1}';
|
||||
// }
|
||||
}
|
||||
.titleBtn {
|
||||
color: ~'@{color-@{value}-btn}';
|
||||
}
|
||||
.play-btn {
|
||||
color: ~'@{color-@{value}-btn}';
|
||||
svg {
|
||||
filter: drop-shadow(0 0 1px rgba(0, 0, 0, 0.3));
|
||||
}
|
||||
}
|
||||
.volume {
|
||||
background-color: ~'@{color-@{value}-player-progress-bar1}';
|
||||
}
|
||||
|
||||
.volume-bar {
|
||||
background-color: ~'@{color-@{value}-btn}';
|
||||
}
|
||||
|
||||
|
||||
.column3 {
|
||||
color: ~'@{color-@{value}-theme_2-font}';
|
||||
}
|
||||
|
||||
.status-text {
|
||||
color: ~'@{color-@{value}-player-status-text}';
|
||||
}
|
||||
|
||||
#icon-pic {
|
||||
color: ~'@{color-@{value}-theme}';
|
||||
.c1 {
|
||||
fill: ~'@{color-@{value}-player-pic-c1}';
|
||||
}
|
||||
.c2 {
|
||||
fill: ~'@{color-@{value}-player-pic-c2}';
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,230 @@
|
||||
<template>
|
||||
<div :class="['right', $style.right]">
|
||||
<div :class="['lyric', $style.lyric, { [$style.draging]: isMsDown }]" @wheel="handleWheel" @mousedown="handleLyricMouseDown" ref="dom_lyric">
|
||||
<div :class="$style.lyricSpace"></div>
|
||||
<div :class="[$style.lyricText]" ref="dom_lyric_text"></div>
|
||||
<div :class="$style.lyricSpace"></div>
|
||||
</div>
|
||||
<transition enter-active-class="animated fadeIn" leave-active-class="animated fadeOut">
|
||||
<div :class="[$style.lyricSelectContent, 'select', 'scroll']" v-if="isShowLrcSelectContent" @contextmenu="handleCopySelectText">
|
||||
<div v-for="(info, index) in lyric.lines" :key="index" :class="[$style.lyricSelectline, { [$style.lrcActive]: lyric.line == index }]">
|
||||
<span>{{info.text}}</span>
|
||||
<br v-if="info.translation"/>
|
||||
<span :class="$style.lyricSelectlineTransition">{{info.translation}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { clipboardWriteText } from '@renderer/utils'
|
||||
import { lyric } from '@renderer/core/share/lyric'
|
||||
import { isPlay, isShowLrcSelectContent } from '@renderer/core/share/player'
|
||||
// import { ref } from '@renderer/utils/vueTools'
|
||||
import useLyric from '@renderer/utils/compositions/useLyric'
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const {
|
||||
dom_lyric,
|
||||
dom_lyric_text,
|
||||
isMsDown,
|
||||
handleLyricMouseDown,
|
||||
handleWheel,
|
||||
} = useLyric({ isPlay, lyric })
|
||||
return {
|
||||
dom_lyric,
|
||||
dom_lyric_text,
|
||||
isMsDown,
|
||||
handleLyricMouseDown,
|
||||
handleWheel,
|
||||
lyric,
|
||||
isShowLrcSelectContent,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleCopySelectText() {
|
||||
let str = window.getSelection().toString()
|
||||
str = str.trim()
|
||||
if (!str.length) return
|
||||
clipboardWriteText(str)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="less" module>
|
||||
@import '@renderer/assets/styles/layout.less';
|
||||
|
||||
.right {
|
||||
flex: 0 0 60%;
|
||||
// padding: 0 30px;
|
||||
position: relative;
|
||||
transition: flex-basis @transition-theme;
|
||||
|
||||
&:before {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
top: 0;
|
||||
left: 0;
|
||||
content: ' ';
|
||||
height: 100px;
|
||||
width: 100%;
|
||||
background-image: linear-gradient(0deg,rgba(255,255,255,0) 0%,@color-theme_2-background_1 95%);
|
||||
pointer-events: none;
|
||||
}
|
||||
&:after {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
content: ' ';
|
||||
height: 100px;
|
||||
width: 100%;
|
||||
background-image: linear-gradient(-180deg,rgba(255,255,255,0) 0%,@color-theme_2-background_1 95%);
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
.lyric {
|
||||
text-align: center;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
font-size: 16px;
|
||||
cursor: grab;
|
||||
&.draging {
|
||||
cursor: grabbing;
|
||||
}
|
||||
:global {
|
||||
.lrc-content {
|
||||
line-height: 1.2;
|
||||
margin: 16px 0;
|
||||
overflow-wrap: break-word;
|
||||
color: @color-player-detail-lyric;
|
||||
|
||||
.translation {
|
||||
transition: @transition-theme !important;
|
||||
transition-property: font-size, color;
|
||||
font-size: .9em;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.line {
|
||||
transition-property: font-size, color !important;
|
||||
background: none !important;
|
||||
-webkit-text-fill-color: unset;
|
||||
// -webkit-text-fill-color: none !important;
|
||||
}
|
||||
&.active {
|
||||
.line {
|
||||
color: @color-theme;
|
||||
}
|
||||
.translation {
|
||||
font-size: 1em;
|
||||
color: @color-theme;
|
||||
}
|
||||
span {
|
||||
// color: @color-theme;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
transition: @transition-theme !important;
|
||||
transition-property: font-size !important;
|
||||
font-size: 1em;
|
||||
background-repeat: no-repeat;
|
||||
background-color: rgba(77, 77, 77, 0.9);
|
||||
background-image: -webkit-linear-gradient(top, @color-theme, @color-theme);
|
||||
-webkit-text-fill-color: transparent;
|
||||
-webkit-background-clip: text;
|
||||
background-size: 0 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
// p {
|
||||
// padding: 8px 0;
|
||||
// line-height: 1.2;
|
||||
// overflow-wrap: break-word;
|
||||
// transition: @transition-theme !important;
|
||||
// transition-property: color, font-size;
|
||||
// }
|
||||
// .lrc-active {
|
||||
// color: @color-theme;
|
||||
// font-size: 1.2em;
|
||||
// }
|
||||
}
|
||||
.lyricSelectContent {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
// text-align: center;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
font-size: 16px;
|
||||
background-color: @color-theme_2-background_1;
|
||||
z-index: 10;
|
||||
color: @color-player-detail-lyric;
|
||||
|
||||
.lyricSelectline {
|
||||
padding: 8px 0;
|
||||
overflow-wrap: break-word;
|
||||
transition: @transition-theme !important;
|
||||
transition-property: color, font-size;
|
||||
line-height: 1.3;
|
||||
}
|
||||
.lyricSelectlineTransition {
|
||||
font-size: 14px;
|
||||
}
|
||||
.lrc-active {
|
||||
color: @color-theme;
|
||||
}
|
||||
}
|
||||
|
||||
.lyric-space {
|
||||
height: 70%;
|
||||
}
|
||||
|
||||
each(@themes, {
|
||||
:global(#root.@{value}) {
|
||||
.right {
|
||||
&:before {
|
||||
background-image: linear-gradient(0deg,rgba(255,255,255,0) 0%,~'@{color-@{value}-theme_2-background_1}' 95%);
|
||||
}
|
||||
&:after {
|
||||
background-image: linear-gradient(-180deg,rgba(255,255,255,0) 0%,~'@{color-@{value}-theme_2-background_1}' 95%);
|
||||
}
|
||||
}
|
||||
.lyric {
|
||||
:global {
|
||||
.lrc-content {
|
||||
color: ~'@{color-@{value}-player-detail-lyric}';
|
||||
|
||||
&.active {
|
||||
.translation {
|
||||
color: ~'@{color-@{value}-player-detail-lyric-active}';
|
||||
}
|
||||
.line {
|
||||
color: ~'@{color-@{value}-player-detail-lyric-active}';
|
||||
}
|
||||
}
|
||||
span {
|
||||
background-color: ~'@{color-@{value}-player-detail-lyric}';
|
||||
background-image: -webkit-linear-gradient(top, ~'@{color-@{value}-player-detail-lyric-active}', ~'@{color-@{value}-player-detail-lyric-active}');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// .lrc-active {
|
||||
// color: ~'@{color-@{value}-theme}';
|
||||
// }
|
||||
.lyricSelectContent {
|
||||
background-color: ~'@{color-@{value}-theme_2-background_1}';
|
||||
color: ~'@{color-@{value}-player-detail-lyric}';
|
||||
.lrc-active {
|
||||
color: ~'@{color-@{value}-theme}';
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,160 @@
|
||||
<template lang="pug">
|
||||
div(:class="$style.footer")
|
||||
div(:class="$style.footerLeft")
|
||||
control-btns
|
||||
div(:class="$style.progressContainer")
|
||||
div(:class="$style.progressContent")
|
||||
common-progress-bar(:class-name="$style.progress" :progress="progress" :handleTransitionEnd="handleTransitionEnd" :isActiveTransition="isActiveTransition")
|
||||
div(:class="$style.timeLabel")
|
||||
span(style="margin-left: 15px") {{status}}
|
||||
div
|
||||
span {{nowPlayTimeStr}}
|
||||
span(style="margin: 0 5px;") /
|
||||
span {{maxPlayTimeStr}}
|
||||
div(:class="$style.playControl")
|
||||
div(:class="$style.playBtn" @click="playPrev" style="transform: rotate(180deg);" :tips="$t('player__prev')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 220.847 220.847' space='preserve')
|
||||
use(xlink:href='#icon-nextMusic')
|
||||
div(:class="$style.playBtn" @click="togglePlay" :tips="isPlay ? $t('player__pause') : $t('player__play')")
|
||||
svg(v-if="isPlay" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 277.338 277.338' space='preserve')
|
||||
use(xlink:href='#icon-pause')
|
||||
svg(v-else version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 170 170' space='preserve')
|
||||
use(xlink:href='#icon-play')
|
||||
div(:class="$style.playBtn" @click="playNext" :tips="$t('player__next')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 220.847 220.847' space='preserve')
|
||||
use(xlink:href='#icon-nextMusic')
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { status, isPlay } from '@renderer/core/share/player'
|
||||
import usePlayProgress from '@renderer/utils/compositions/usePlayProgress'
|
||||
import { player as eventPlayerNames } from '@renderer/event/names'
|
||||
|
||||
import ControlBtns from './components/ControlBtns'
|
||||
export default {
|
||||
components: {
|
||||
ControlBtns,
|
||||
},
|
||||
setup() {
|
||||
const {
|
||||
nowPlayTimeStr,
|
||||
maxPlayTimeStr,
|
||||
progress,
|
||||
isActiveTransition,
|
||||
handleTransitionEnd,
|
||||
} = usePlayProgress()
|
||||
|
||||
return {
|
||||
nowPlayTimeStr,
|
||||
maxPlayTimeStr,
|
||||
status,
|
||||
progress,
|
||||
isActiveTransition,
|
||||
handleTransitionEnd,
|
||||
isPlay,
|
||||
togglePlay() {
|
||||
window.eventHub.emit(eventPlayerNames.setTogglePlay)
|
||||
},
|
||||
playNext() {
|
||||
window.eventHub.emit(eventPlayerNames.setPlayNext)
|
||||
},
|
||||
playPrev() {
|
||||
window.eventHub.emit(eventPlayerNames.setPlayPrev)
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" module>
|
||||
@import '@renderer/assets/styles/layout.less';
|
||||
|
||||
.footer {
|
||||
flex: 0 0 100px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.footerLeft {
|
||||
flex: auto;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
padding: 13px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.progress-container {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
padding: 3px 0;
|
||||
}
|
||||
|
||||
.progress-content {
|
||||
position: relative;
|
||||
height: 15px;
|
||||
padding: 5px 0;
|
||||
width: 100%;
|
||||
}
|
||||
.progress {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.bar-transition {
|
||||
transition-property: transform;
|
||||
transition-timing-function: ease-out;
|
||||
transition-duration: 0.2s;
|
||||
}
|
||||
.time-label {
|
||||
width: 100%;
|
||||
height: 18px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
span {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
.play-control {
|
||||
flex: none;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
padding: 0 25px;
|
||||
color: @color-btn;
|
||||
}
|
||||
.play-btn {
|
||||
height: 40%;
|
||||
padding: 5px;
|
||||
cursor: pointer;
|
||||
flex: none;
|
||||
// transition: @transition-theme;
|
||||
// transition-property: color;
|
||||
color: @color-player-detail-play-btn;
|
||||
transition: opacity 0.2s ease;
|
||||
opacity: 1;
|
||||
cursor: pointer;
|
||||
|
||||
+.play-btn {
|
||||
margin-left: 10px;
|
||||
}
|
||||
svg {
|
||||
fill: currentColor;
|
||||
filter: drop-shadow(0 0 1px rgba(0, 0, 0, 0.2));
|
||||
}
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
&:active {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
each(@themes, {
|
||||
:global(#root.@{value}) {
|
||||
.play-btn {
|
||||
color: ~'@{color-@{value}-player-detail-play-btn}';
|
||||
}
|
||||
}
|
||||
})
|
||||
</style>
|
||||
@@ -0,0 +1,142 @@
|
||||
<template lang="pug">
|
||||
div(:class="$style.footerLeftControlBtns")
|
||||
common-volume-bar(:setting="setting")
|
||||
div(:class="[$style.footerLeftControlBtn, $style.lrcBtn]" @click="toggleDesktopLyric" @contextmenu="toggleLockDesktopLyric" :tips="toggleDesktopLyricBtnTitle")
|
||||
svg(v-if="setting.desktopLyric.enable" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='125%' viewBox='0 0 512 512' space='preserve')
|
||||
use(xlink:href='#icon-desktop-lyric-on')
|
||||
svg(v-else version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='125%' viewBox='0 0 512 512' space='preserve')
|
||||
use(xlink:href='#icon-desktop-lyric-off')
|
||||
div(:class="[$style.footerLeftControlBtn, { [$style.active]: isShowLrcSelectContent }]" @click="toggleVisibleLrc" :tips="$t('lyric__select')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='95%' viewBox='0 0 24 24' space='preserve')
|
||||
use(xlink:href='#icon-text')
|
||||
div(:class="[$style.footerLeftControlBtn, {[$style.active]: isShowPlayComment}]" @click="toggleVisibleComment" :tips="$t('comment__show')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='95%' viewBox='0 0 24 24' space='preserve')
|
||||
use(xlink:href='#icon-comment')
|
||||
div(:class="$style.footerLeftControlBtn" @click="toggleNextPlayMode" :tips="nextTogglePlayName")
|
||||
svg(v-if="setting.player.togglePlayMethod == 'listLoop'" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' viewBox='0 0 24 24' space='preserve')
|
||||
use(xlink:href='#icon-list-loop')
|
||||
svg(v-else-if="setting.player.togglePlayMethod == 'random'" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' viewBox='0 0 24 24' space='preserve')
|
||||
use(xlink:href='#icon-list-random')
|
||||
svg(v-else-if="setting.player.togglePlayMethod == 'list'" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='120%' viewBox='0 0 24 24' space='preserve')
|
||||
use(xlink:href='#icon-list-order')
|
||||
svg(v-else-if="setting.player.togglePlayMethod == 'singleLoop'" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='110%' viewBox='0 0 24 24' space='preserve')
|
||||
use(xlink:href='#icon-single-loop')
|
||||
svg(v-else version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='120%' viewBox='0 0 24 24' space='preserve')
|
||||
use(xlink:href='#icon-single')
|
||||
div(:class="$style.footerLeftControlBtn" @click="isShowAddMusicTo = true" :tips="$t('player__add_music_to')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' viewBox='0 0 512 512' space='preserve')
|
||||
use(xlink:href='#icon-add-2')
|
||||
teleport(to="#root")
|
||||
common-list-add-modal(:show="isShowAddMusicTo" :musicInfo="musicInfoItem" @close="isShowAddMusicTo = false")
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useI18n, useRefGetter, ref } from '@renderer/utils/vueTools'
|
||||
|
||||
import {
|
||||
isShowLrcSelectContent,
|
||||
setShowPlayLrcSelectContentLrc,
|
||||
isShowPlayComment,
|
||||
setShowPlayComment,
|
||||
musicInfoItem,
|
||||
} from '@renderer/core/share/player'
|
||||
|
||||
import useNextTogglePlay from '@renderer/utils/compositions/useNextTogglePlay'
|
||||
import useToggleDesktopLyric from '@renderer/utils/compositions/useToggleDesktopLyric'
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const { t } = useI18n()
|
||||
const setting = useRefGetter('setting')
|
||||
|
||||
const toggleVisibleLrc = () => {
|
||||
setShowPlayLrcSelectContentLrc(!isShowLrcSelectContent.value)
|
||||
}
|
||||
const toggleVisibleComment = () => {
|
||||
setShowPlayComment(!isShowPlayComment.value)
|
||||
}
|
||||
const {
|
||||
nextTogglePlayName,
|
||||
toggleNextPlayMode,
|
||||
} = useNextTogglePlay({ setting, t })
|
||||
|
||||
const {
|
||||
toggleDesktopLyricBtnTitle,
|
||||
toggleDesktopLyric,
|
||||
toggleLockDesktopLyric,
|
||||
} = useToggleDesktopLyric({ setting, t })
|
||||
|
||||
const isShowAddMusicTo = ref(false)
|
||||
|
||||
return {
|
||||
setting,
|
||||
isShowLrcSelectContent,
|
||||
toggleVisibleLrc,
|
||||
isShowPlayComment,
|
||||
toggleVisibleComment,
|
||||
nextTogglePlayName,
|
||||
toggleNextPlayMode,
|
||||
toggleDesktopLyricBtnTitle,
|
||||
toggleDesktopLyric,
|
||||
toggleLockDesktopLyric,
|
||||
isShowAddMusicTo,
|
||||
musicInfoItem,
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" module>
|
||||
@import '@renderer/assets/styles/layout.less';
|
||||
|
||||
.footerLeftControlBtns {
|
||||
color: @color-theme_2-font;
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
justify-content: flex-end;
|
||||
|
||||
.footerLeftControlBtn {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
opacity: .5;
|
||||
cursor: pointer;
|
||||
transition: opacity @transition-theme;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&:hover {
|
||||
opacity: .9;
|
||||
}
|
||||
|
||||
+.footerLeftControlBtn {
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: @color-theme;
|
||||
opacity: .8;
|
||||
}
|
||||
}
|
||||
|
||||
.lrcBtn {
|
||||
width: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
each(@themes, {
|
||||
:global(#root.@{value}) {
|
||||
.footerLeftControlBtns {
|
||||
color: ~'@{color-@{value}-theme_2-font}';
|
||||
}
|
||||
.footerLeftControlBtn {
|
||||
&.active {
|
||||
color: ~'@{color-@{value}-theme}';
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,538 @@
|
||||
<template lang="pug">
|
||||
transition(enter-active-class="animated lightSpeedIn" leave-active-class="animated slideOutDown" @after-enter="handleAfterEnter" @after-leave="handleAfterLeave")
|
||||
div(:class="[$style.container, setting.controlBtnPosition == 'left' ? $style.controlBtnLeft : $style.controlBtnRight]" @contextmenu="handleContextMenu" v-if="isShowPlayerDetail")
|
||||
//- div(:class="$style.bg" :style="bgStyle")
|
||||
//- div(:class="$style.bg2")
|
||||
div(:class="$style.header")
|
||||
div(:class="$style.controBtn")
|
||||
button(type="button" :class="$style.hide" :tips="$t('player__hide_detail_tip')" @click="hide")
|
||||
svg(:class="$style.controBtnIcon" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='80%' viewBox='0 0 30.727 30.727' space='preserve')
|
||||
use(xlink:href='#icon-window-hide')
|
||||
button(type="button" :class="$style.min" :tips="$t('min')" @click="min")
|
||||
svg(:class="$style.controBtnIcon" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='100%' viewBox='0 0 24 24' space='preserve')
|
||||
use(xlink:href='#icon-window-minimize')
|
||||
|
||||
//- button(type="button" :class="$style.max" @click="max")
|
||||
button(type="button" :class="$style.close" :tips="$t('close')" @click="close")
|
||||
svg(:class="$style.controBtnIcon" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='100%' viewBox='0 0 24 24' space='preserve')
|
||||
use(xlink:href='#icon-window-close')
|
||||
|
||||
div(:class="[$style.main, {[$style.showComment]: isShowPlayComment}]")
|
||||
div.left(:class="$style.left")
|
||||
//- div(:class="$style.info")
|
||||
div(:class="$style.info")
|
||||
img(:class="$style.img" :src="musicInfo.img" v-if="musicInfo.img")
|
||||
div.description(:class="$style.description")
|
||||
p {{$t('player__music_name')}}{{musicInfo.name}}
|
||||
p {{$t('player__music_singer')}}{{musicInfo.singer}}
|
||||
p(v-if="musicInfo.album") {{$t('player__music_album')}}{{musicInfo.album}}
|
||||
|
||||
transition(enter-active-class="animated fadeIn" leave-active-class="animated fadeOut")
|
||||
Lyric(v-if="visibleLrc")
|
||||
core-music-comment(:class="$style.comment" :musicInfo="musicInfoItem" :show="isShowPlayComment" @close="hideComment")
|
||||
play-bar
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
import { useRefGetter, ref } from '@renderer/utils/vueTools'
|
||||
import { base as eventBaseName } from '@renderer/event/names'
|
||||
import {
|
||||
isShowPlayerDetail,
|
||||
setShowPlayerDetail,
|
||||
isShowPlayComment,
|
||||
setShowPlayComment,
|
||||
setShowPlayLrcSelectContentLrc,
|
||||
musicInfoItem,
|
||||
musicInfo,
|
||||
} from '@renderer/core/share/player'
|
||||
import Lyric from './Lyric'
|
||||
import PlayBar from './PlayBar'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Lyric,
|
||||
PlayBar,
|
||||
},
|
||||
setup() {
|
||||
const setting = useRefGetter('setting')
|
||||
const visibleLrc = ref(false)
|
||||
|
||||
let clickTime = 0
|
||||
|
||||
const hide = () => {
|
||||
setShowPlayerDetail(false)
|
||||
}
|
||||
const handleContextMenu = () => {
|
||||
if (window.performance.now() - clickTime > 400) {
|
||||
clickTime = window.performance.now()
|
||||
return
|
||||
}
|
||||
clickTime = 0
|
||||
hide()
|
||||
}
|
||||
|
||||
const hideComment = () => {
|
||||
setShowPlayComment(false)
|
||||
}
|
||||
|
||||
const handleAfterEnter = () => {
|
||||
visibleLrc.value = true
|
||||
}
|
||||
|
||||
const handleAfterLeave = () => {
|
||||
setShowPlayLrcSelectContentLrc(false)
|
||||
hideComment(false)
|
||||
visibleLrc.value = false
|
||||
}
|
||||
|
||||
return {
|
||||
setting,
|
||||
isShowPlayerDetail,
|
||||
isShowPlayComment,
|
||||
musicInfoItem,
|
||||
musicInfo,
|
||||
hide,
|
||||
handleContextMenu,
|
||||
hideComment,
|
||||
handleAfterEnter,
|
||||
handleAfterLeave,
|
||||
visibleLrc,
|
||||
min() {
|
||||
window.eventHub.emit(eventBaseName.min)
|
||||
},
|
||||
max() {
|
||||
window.eventHub.emit(eventBaseName.max)
|
||||
},
|
||||
close() {
|
||||
window.eventHub.emit(eventBaseName.close)
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="less" module>
|
||||
@import '@renderer/assets/styles/layout.less';
|
||||
|
||||
@control-btn-width: @height-toolbar * .26;
|
||||
|
||||
.container {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-color: @color-theme_2-background_1;
|
||||
z-index: 10;
|
||||
// -webkit-app-region: drag;
|
||||
overflow: hidden;
|
||||
border-radius: @radius-border;
|
||||
color: @color-theme_2-font;
|
||||
border-left: 12px solid @color-theme;
|
||||
-webkit-app-region: no-drag;
|
||||
|
||||
box-sizing: border-box;
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
&.controlBtnLeft {
|
||||
.controBtn {
|
||||
left: 0;
|
||||
flex-direction: row-reverse;
|
||||
height: @height-toolbar * .7;
|
||||
button + button {
|
||||
margin-right: @control-btn-width / 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.controlBtnRight {
|
||||
.controBtn {
|
||||
right: @control-btn-width * .5;
|
||||
button + button {
|
||||
margin-left: @control-btn-width * 1.2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
.bg {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-size: 110% 110%;
|
||||
filter: blur(60px);
|
||||
z-index: -1;
|
||||
}
|
||||
.bg2 {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: -1;
|
||||
background-color: rgba(255, 255, 255, .8);
|
||||
}
|
||||
|
||||
.header {
|
||||
position: relative;
|
||||
flex: 0 0 @height-toolbar;
|
||||
-webkit-app-region: drag;
|
||||
}
|
||||
|
||||
.controBtn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: @height-toolbar;
|
||||
-webkit-app-region: no-drag;
|
||||
padding: 0 @control-btn-width;
|
||||
&:hover {
|
||||
.controBtnIcon {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
position: relative;
|
||||
width: @control-btn-width;
|
||||
height: @control-btn-width;
|
||||
background: none;
|
||||
border: none;
|
||||
outline: none;
|
||||
padding: 1px;
|
||||
cursor: pointer;
|
||||
border-radius: 50%;
|
||||
color: @color-theme_2;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
&.hide {
|
||||
background-color: @color-hideBtn;
|
||||
}
|
||||
&.min {
|
||||
background-color: @color-minBtn;
|
||||
}
|
||||
&.max {
|
||||
background-color: @color-maxBtn;
|
||||
}
|
||||
&.close {
|
||||
background-color: @color-closeBtn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.controBtnIcon {
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.main {
|
||||
flex: auto;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
margin: 0 30px;
|
||||
position: relative;
|
||||
|
||||
&.showComment {
|
||||
:global {
|
||||
.left {
|
||||
flex-basis: 18%;
|
||||
.description p {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
.right {
|
||||
flex-basis: 30%;
|
||||
.lyric {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
.comment {
|
||||
opacity: 1;
|
||||
transform: scaleX(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.left {
|
||||
flex: 0 0 40%;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
align-items: center;
|
||||
padding: 13px;
|
||||
overflow: hidden;
|
||||
transition: flex-basis @transition-theme;
|
||||
}
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
justify-content: flex-start;
|
||||
max-width: 300px;
|
||||
|
||||
}
|
||||
.img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
min-width: 100%;
|
||||
box-shadow: 0 0 4px @color-theme-hover;
|
||||
border-radius: 6px;
|
||||
opacity: .8;
|
||||
// border: 5px solid @color-theme-hover;
|
||||
// border-radius: @radius-border;
|
||||
// border: 5px solid #fff;
|
||||
}
|
||||
.description {
|
||||
max-width: 300px;
|
||||
padding: 15px 0;
|
||||
overflow: hidden;
|
||||
p {
|
||||
line-height: 1.5;
|
||||
font-size: 14px;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
flex: 0 0 60%;
|
||||
// padding: 0 30px;
|
||||
position: relative;
|
||||
transition: flex-basis @transition-theme;
|
||||
|
||||
&:before {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
top: 0;
|
||||
left: 0;
|
||||
content: ' ';
|
||||
height: 100px;
|
||||
width: 100%;
|
||||
background-image: linear-gradient(0deg,rgba(255,255,255,0) 0%,@color-theme_2-background_1 95%);
|
||||
pointer-events: none;
|
||||
}
|
||||
&:after {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
content: ' ';
|
||||
height: 100px;
|
||||
width: 100%;
|
||||
background-image: linear-gradient(-180deg,rgba(255,255,255,0) 0%,@color-theme_2-background_1 95%);
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
.lyric {
|
||||
text-align: center;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
font-size: 16px;
|
||||
cursor: grab;
|
||||
&.draging {
|
||||
cursor: grabbing;
|
||||
}
|
||||
:global {
|
||||
.lrc-content {
|
||||
line-height: 1.2;
|
||||
margin: 16px 0;
|
||||
overflow-wrap: break-word;
|
||||
color: @color-player-detail-lyric;
|
||||
|
||||
.translation {
|
||||
transition: @transition-theme !important;
|
||||
transition-property: font-size, color;
|
||||
font-size: .9em;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.line {
|
||||
transition-property: font-size, color !important;
|
||||
background: none !important;
|
||||
-webkit-text-fill-color: unset;
|
||||
// -webkit-text-fill-color: none !important;
|
||||
}
|
||||
&.active {
|
||||
.line {
|
||||
color: @color-theme;
|
||||
}
|
||||
.translation {
|
||||
font-size: 1em;
|
||||
color: @color-theme;
|
||||
}
|
||||
span {
|
||||
// color: @color-theme;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
transition: @transition-theme !important;
|
||||
transition-property: font-size !important;
|
||||
font-size: 1em;
|
||||
background-repeat: no-repeat;
|
||||
background-color: rgba(77, 77, 77, 0.9);
|
||||
background-image: -webkit-linear-gradient(top, @color-theme, @color-theme);
|
||||
-webkit-text-fill-color: transparent;
|
||||
-webkit-background-clip: text;
|
||||
background-size: 0 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
// p {
|
||||
// padding: 8px 0;
|
||||
// line-height: 1.2;
|
||||
// overflow-wrap: break-word;
|
||||
// transition: @transition-theme !important;
|
||||
// transition-property: color, font-size;
|
||||
// }
|
||||
// .lrc-active {
|
||||
// color: @color-theme;
|
||||
// font-size: 1.2em;
|
||||
// }
|
||||
}
|
||||
.lyricSelectContent {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
// text-align: center;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
font-size: 16px;
|
||||
background-color: @color-theme_2-background_1;
|
||||
z-index: 10;
|
||||
color: @color-player-detail-lyric;
|
||||
|
||||
.lyricSelectline {
|
||||
padding: 8px 0;
|
||||
overflow-wrap: break-word;
|
||||
transition: @transition-theme !important;
|
||||
transition-property: color, font-size;
|
||||
line-height: 1.3;
|
||||
}
|
||||
.lyricSelectlineTransition {
|
||||
font-size: 14px;
|
||||
}
|
||||
.lrc-active {
|
||||
color: @color-theme;
|
||||
}
|
||||
}
|
||||
|
||||
.lyric-space {
|
||||
height: 70%;
|
||||
}
|
||||
|
||||
.comment {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
opacity: 1;
|
||||
margin-left: 10px;
|
||||
transform: scaleX(0);
|
||||
}
|
||||
|
||||
|
||||
each(@themes, {
|
||||
:global(#root.@{value}) {
|
||||
.container {
|
||||
border-left-color: ~'@{color-@{value}-theme}';
|
||||
background-color: ~'@{color-@{value}-theme_2-background_1}';
|
||||
// color: ~'@{color-@{value}-theme_2-font}';
|
||||
}
|
||||
.right {
|
||||
&:before {
|
||||
background-image: linear-gradient(0deg,rgba(255,255,255,0) 0%,~'@{color-@{value}-theme_2-background_1}' 95%);
|
||||
}
|
||||
&:after {
|
||||
background-image: linear-gradient(-180deg,rgba(255,255,255,0) 0%,~'@{color-@{value}-theme_2-background_1}' 95%);
|
||||
}
|
||||
}
|
||||
.controBtn {
|
||||
button {
|
||||
color: ~'@{color-@{value}-theme_2}';
|
||||
// &.hide:after {
|
||||
// background-color: ~'@{color-@{value}-hideBtn}';
|
||||
// }
|
||||
&.hide {
|
||||
background-color: ~'@{color-@{value}-hideBtn}';
|
||||
}
|
||||
&.min {
|
||||
background-color: ~'@{color-@{value}-minBtn}';
|
||||
}
|
||||
&.max {
|
||||
background-color: ~'@{color-@{value}-maxBtn}';
|
||||
}
|
||||
&.close {
|
||||
background-color: ~'@{color-@{value}-closeBtn}';
|
||||
}
|
||||
}
|
||||
}
|
||||
.img {
|
||||
box-shadow: 0 0 4px ~'@{color-@{value}-theme-hover}';
|
||||
// border-color: ~'@{color-@{value}-theme-hover}';
|
||||
}
|
||||
.lyric {
|
||||
:global {
|
||||
.lrc-content {
|
||||
color: ~'@{color-@{value}-player-detail-lyric}';
|
||||
|
||||
&.active {
|
||||
.translation {
|
||||
color: ~'@{color-@{value}-player-detail-lyric-active}';
|
||||
}
|
||||
.line {
|
||||
color: ~'@{color-@{value}-player-detail-lyric-active}';
|
||||
}
|
||||
}
|
||||
span {
|
||||
background-color: ~'@{color-@{value}-player-detail-lyric}';
|
||||
background-image: -webkit-linear-gradient(top, ~'@{color-@{value}-player-detail-lyric-active}', ~'@{color-@{value}-player-detail-lyric-active}');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// .lrc-active {
|
||||
// color: ~'@{color-@{value}-theme}';
|
||||
// }
|
||||
.lyricSelectContent {
|
||||
background-color: ~'@{color-@{value}-theme_2-background_1}';
|
||||
color: ~'@{color-@{value}-player-detail-lyric}';
|
||||
.lrc-active {
|
||||
color: ~'@{color-@{value}-theme}';
|
||||
}
|
||||
}
|
||||
.footerLeftControlBtns {
|
||||
color: ~'@{color-@{value}-theme_2-font}';
|
||||
}
|
||||
.footerLeftControlBtn {
|
||||
&.active {
|
||||
color: ~'@{color-@{value}-theme}';
|
||||
}
|
||||
}
|
||||
.progress {
|
||||
background-color: ~'@{color-@{value}-player-progress}';
|
||||
}
|
||||
.progress-bar1 {
|
||||
background-color: ~'@{color-@{value}-player-progress-bar1}';
|
||||
}
|
||||
.progress-bar2 {
|
||||
background-color: ~'@{color-@{value}-player-progress-bar2}';
|
||||
}
|
||||
.play-btn {
|
||||
color: ~'@{color-@{value}-player-detail-play-btn}';
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
</style>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,943 +0,0 @@
|
||||
<template lang="pug">
|
||||
div(:class="[$style.container, setting.controlBtnPosition == 'left' ? $style.controlBtnLeft : $style.controlBtnRight]" @contextmenu="handleContextMenu")
|
||||
//- div(:class="$style.bg" :style="bgStyle")
|
||||
//- div(:class="$style.bg2")
|
||||
div(:class="$style.header")
|
||||
div(:class="$style.controBtn")
|
||||
button(type="button" :class="$style.hide" :tips="$t('core.player.hide_detail')" @click="hide")
|
||||
svg(:class="$style.controBtnIcon" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='80%' viewBox='0 0 30.727 30.727' space='preserve')
|
||||
use(xlink:href='#icon-window-hide')
|
||||
button(type="button" :class="$style.min" :tips="$t('core.toolbar.min')" @click="min")
|
||||
svg(:class="$style.controBtnIcon" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='100%' viewBox='0 0 24 24' space='preserve')
|
||||
use(xlink:href='#icon-window-minimize')
|
||||
|
||||
//- button(type="button" :class="$style.max" @click="max")
|
||||
button(type="button" :class="$style.close" :tips="$t('core.toolbar.close')" @click="close")
|
||||
svg(:class="$style.controBtnIcon" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='100%' viewBox='0 0 24 24' space='preserve')
|
||||
use(xlink:href='#icon-window-close')
|
||||
|
||||
div(:class="[$style.main, isShowComment ? $style.showComment : null]")
|
||||
div(:class="$style.left")
|
||||
//- div(:class="$style.info")
|
||||
div(:class="$style.info")
|
||||
img(:class="$style.img" :src="musicInfo.img" v-if="musicInfo.img")
|
||||
div(:class="$style.description")
|
||||
p {{$t('core.player.name')}}{{musicInfo.name}}
|
||||
p {{$t('core.player.singer')}}{{musicInfo.singer}}
|
||||
p(v-if="musicInfo.album") {{$t('core.player.album')}}{{musicInfo.album}}
|
||||
|
||||
div(:class="$style.right")
|
||||
div(:class="[$style.lyric, { [$style.draging]: lyricEvent.isMsDown }]" @wheel="handleWheel" @mousedown="handleLyricMouseDown" ref="dom_lyric")
|
||||
div(:class="$style.lyricSpace")
|
||||
div(:class="[$style.lyricText]" ref="dom_lyric_text")
|
||||
//- p(v-for="(info, index) in lyricLines" :key="index" :class="lyric.line == index ? $style.lrcActive : null") {{info.text}}
|
||||
div(:class="$style.lyricSpace")
|
||||
transition(enter-active-class="animated fadeIn" leave-active-class="animated fadeOut")
|
||||
div(:class="[$style.lyricSelectContent, 'select', 'scroll']" v-if="isShowLrcSelectContent" @contextmenu="handleCopySelectText")
|
||||
//- div(:class="$style.lyricSpace")
|
||||
div(v-for="(info, index) in lyricLines" :key="index" :class="[$style.lyricSelectline, { [$style.lrcActive]: lyric.line == index }]")
|
||||
span {{info.text}}
|
||||
br(v-if="info.translation")
|
||||
span(:class="$style.lyricSelectlineTransition") {{info.translation}}
|
||||
//- div(:class="$style.lyricSpace")
|
||||
|
||||
material-music-comment(:class="$style.comment" :titleFormat="this.setting.download.fileName" :musicInfo="musicInfo" v-model="isShowComment")
|
||||
|
||||
div(:class="$style.footer")
|
||||
div(:class="$style.footerLeft")
|
||||
div(:class="$style.footerLeftControlBtns")
|
||||
div(:class="[$style.footerLeftControlBtn, { [$style.active]: isShowLrcSelectContent }]" @click="isShowLrcSelectContent = !isShowLrcSelectContent" :tips="$t('core.player.lyric_select')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='95%' viewBox='0 0 24 24' space='preserve')
|
||||
use(xlink:href='#icon-text')
|
||||
div(:class="[$style.footerLeftControlBtn, isShowComment ? $style.active : null]" @click="isShowComment = !isShowComment" :tips="$t('core.player.comment_show')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='95%' viewBox='0 0 24 24' space='preserve')
|
||||
use(xlink:href='#icon-comment')
|
||||
div(:class="$style.footerLeftControlBtn" @click="$emit('toggle-next-play-mode')" :tips="nextTogglePlayName")
|
||||
svg(v-if="setting.player.togglePlayMethod == 'listLoop'" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' viewBox='0 0 24 24' space='preserve')
|
||||
use(xlink:href='#icon-list-loop')
|
||||
svg(v-else-if="setting.player.togglePlayMethod == 'random'" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' viewBox='0 0 24 24' space='preserve')
|
||||
use(xlink:href='#icon-list-random')
|
||||
svg(v-else-if="setting.player.togglePlayMethod == 'list'" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='120%' viewBox='0 0 24 24' space='preserve')
|
||||
use(xlink:href='#icon-list-order')
|
||||
svg(v-else-if="setting.player.togglePlayMethod == 'singleLoop'" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='110%' viewBox='0 0 24 24' space='preserve')
|
||||
use(xlink:href='#icon-single-loop')
|
||||
svg(v-else version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='120%' viewBox='0 0 24 24' space='preserve')
|
||||
use(xlink:href='#icon-single')
|
||||
div(:class="$style.footerLeftControlBtn" @click="$emit('add-music-to', musicInfo)" :tips="$t('core.player.add_music_to')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' viewBox='0 0 512 512' space='preserve')
|
||||
use(xlink:href='#icon-add-2')
|
||||
div(:class="$style.progressContainer")
|
||||
div(:class="$style.progressContent")
|
||||
div(:class="$style.progress")
|
||||
//- div(:class="[$style.progressBar, $style.progressBar1]" :style="{ transform: `scaleX(${progress || 0})` }")
|
||||
div(:class="[$style.progressBar, $style.progressBar2, isActiveTransition ? $style.barTransition : '']" @transitionend="handleTransitionEnd" :style="{ transform: `scaleX(${playInfo.progress || 0})` }")
|
||||
div(:class="$style.progressMask" @click='setProgress' ref="dom_progress")
|
||||
div(:class="$style.timeLabel")
|
||||
span(style="margin-left: 15px") {{playInfo.status}}
|
||||
div
|
||||
span {{playInfo.nowPlayTimeStr}}
|
||||
span(style="margin: 0 5px;") /
|
||||
span {{playInfo.maxPlayTimeStr}}
|
||||
div(:class="$style.playControl")
|
||||
//- div(:class="$style.playBtn")
|
||||
//- div(:class="$style.playBtn")
|
||||
div(:class="$style.playBtn" @click="$emit('action', { type: 'prev' })" style="transform: rotate(180deg);" :tips="$t('core.player.prev')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 220.847 220.847' space='preserve')
|
||||
use(xlink:href='#icon-nextMusic')
|
||||
div(:class="$style.playBtn" :tips="isPlay ? $t('core.player.pause') : $t('core.player.play')" @click="$emit('action', { type: 'togglePlay' })")
|
||||
svg(v-if="isPlay" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 277.338 277.338' space='preserve')
|
||||
use(xlink:href='#icon-pause')
|
||||
svg(v-else version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 170 170' space='preserve')
|
||||
use(xlink:href='#icon-play')
|
||||
div(:class="$style.playBtn" @click="$emit('action', { type: 'next' })" :tips="$t('core.player.next')")
|
||||
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 220.847 220.847' space='preserve')
|
||||
use(xlink:href='#icon-nextMusic')
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import { base as eventBaseName } from '../../event/names'
|
||||
import { clipboardWriteText, scrollTo } from '../../utils'
|
||||
|
||||
let cancelScrollFn = null
|
||||
|
||||
export default {
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
musicInfo: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {
|
||||
songmid: null,
|
||||
img: null,
|
||||
lrc: null,
|
||||
url: null,
|
||||
name: '^',
|
||||
singer: '^',
|
||||
}
|
||||
},
|
||||
},
|
||||
lyric: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {
|
||||
line: 0,
|
||||
text: '',
|
||||
lines: [],
|
||||
}
|
||||
},
|
||||
},
|
||||
playInfo: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {
|
||||
nowPlayTimeStr: '00:00',
|
||||
maxPlayTimeStr: '00:00',
|
||||
progress: 0,
|
||||
nowPlayTime: 0,
|
||||
status: 0,
|
||||
}
|
||||
},
|
||||
},
|
||||
list: {
|
||||
type: Array,
|
||||
default() {
|
||||
return []
|
||||
},
|
||||
},
|
||||
listId: {
|
||||
type: String,
|
||||
default() {
|
||||
return ''
|
||||
},
|
||||
},
|
||||
isPlay: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
nextTogglePlayName: String,
|
||||
},
|
||||
watch: {
|
||||
// 'musicInfo.img': {
|
||||
// handler(n) {
|
||||
// if (n) {
|
||||
// this.bgStyle.backgroundImage = `url(${n})`
|
||||
// }
|
||||
// },
|
||||
// immediate: true,
|
||||
// },
|
||||
'lyric.lines': {
|
||||
handler(n, o) {
|
||||
this.isSetedLines = true
|
||||
if (o) {
|
||||
this.$refs.dom_lyric_text.textContent = ''
|
||||
this.setLyric(n)
|
||||
|
||||
this._lyricLines = n
|
||||
if (n.length) {
|
||||
this.lyricLines = n
|
||||
this.$nextTick(() => {
|
||||
this.dom_lines = this.$refs.dom_lyric.querySelectorAll('.lrc-content')
|
||||
this.handleScrollLrc()
|
||||
})
|
||||
} else {
|
||||
if (cancelScrollFn) {
|
||||
cancelScrollFn()
|
||||
cancelScrollFn = null
|
||||
}
|
||||
cancelScrollFn = scrollTo(this.$refs.dom_lyric, 0, 300, () => {
|
||||
if (this.lyricLines === this._lyricLines && this._lyricLines.length) return
|
||||
this.lyricLines = this._lyricLines
|
||||
this.$nextTick(() => {
|
||||
this.dom_lines = this.$refs.dom_lyric.querySelectorAll('.lrc-content')
|
||||
this.handleScrollLrc()
|
||||
})
|
||||
}, 50)
|
||||
}
|
||||
} else {
|
||||
this.lyricLines = n
|
||||
this.$nextTick(() => {
|
||||
this.dom_lines = this.$refs.dom_lyric.querySelectorAll('.lrc-content')
|
||||
this.handleScrollLrc()
|
||||
})
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
'lyric.line': {
|
||||
handler(n) {
|
||||
if (n < 0) return
|
||||
if (n == 0 && this.isSetedLines) return this.isSetedLines = false
|
||||
this.handleScrollLrc()
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
'playInfo.nowPlayTime'(n, o) {
|
||||
if (Math.abs(n - o) > 2) this.isActiveTransition = true
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
bgStyle: {
|
||||
backgroundImage: null,
|
||||
},
|
||||
dom_lines: [],
|
||||
isActiveTransition: false,
|
||||
pregessWidth: 0,
|
||||
clickTime: 0,
|
||||
lyricEvent: {
|
||||
isMsDown: false,
|
||||
msDownY: 0,
|
||||
msDownScrollY: 0,
|
||||
isStopScroll: false,
|
||||
timeout: null,
|
||||
},
|
||||
_lyricLines: [],
|
||||
lyricLines: [],
|
||||
isSetedLines: false,
|
||||
isShowComment: false,
|
||||
isShowLrcSelectContent: false,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.setProgressWidth()
|
||||
})
|
||||
this.listenEvent()
|
||||
|
||||
// console.log('object', this.$refs.dom_lyric_text)
|
||||
this.setLyric(this.lyricLines)
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.unlistenEvent()
|
||||
|
||||
this.clearLyricScrollTimeout()
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['setting']),
|
||||
},
|
||||
methods: {
|
||||
hide() {
|
||||
this.$emit('update:visible', false)
|
||||
},
|
||||
listenEvent() {
|
||||
document.addEventListener('mousemove', this.handleMouseMsMove)
|
||||
document.addEventListener('mouseup', this.handleMouseMsUp)
|
||||
window.addEventListener('resize', this.handleResize)
|
||||
},
|
||||
unlistenEvent() {
|
||||
document.removeEventListener('mousemove', this.handleMouseMsMove)
|
||||
document.removeEventListener('mouseup', this.handleMouseMsUp)
|
||||
window.removeEventListener('resize', this.handleResize)
|
||||
},
|
||||
setLyric(lines) {
|
||||
const dom_lines = document.createDocumentFragment()
|
||||
for (const line of lines) {
|
||||
dom_lines.appendChild(line.dom_line)
|
||||
}
|
||||
this.$refs.dom_lyric_text.appendChild(dom_lines)
|
||||
},
|
||||
handleResize() {
|
||||
this.setProgressWidth()
|
||||
},
|
||||
handleScrollLrc() {
|
||||
if (!this.dom_lines.length) return
|
||||
if (cancelScrollFn) {
|
||||
cancelScrollFn()
|
||||
cancelScrollFn = null
|
||||
}
|
||||
if (this.lyricEvent.isStopScroll) return
|
||||
let dom_p = this.dom_lines[this.lyric.line]
|
||||
cancelScrollFn = scrollTo(this.$refs.dom_lyric, dom_p ? (dom_p.offsetTop - this.$refs.dom_lyric.clientHeight * 0.38) : 0)
|
||||
},
|
||||
handleTransitionEnd() {
|
||||
this.isActiveTransition = false
|
||||
},
|
||||
setProgress(event) {
|
||||
this.$emit('action', {
|
||||
type: 'progress',
|
||||
data: event.offsetX / this.pregessWidth,
|
||||
})
|
||||
},
|
||||
setProgressWidth() {
|
||||
this.pregessWidth = parseInt(
|
||||
window.getComputedStyle(this.$refs.dom_progress, null).width,
|
||||
)
|
||||
},
|
||||
handleContextMenu() {
|
||||
if (window.performance.now() - this.clickTime > 400) {
|
||||
this.clickTime = window.performance.now()
|
||||
return
|
||||
}
|
||||
this.clickTime = 0
|
||||
this.hide()
|
||||
},
|
||||
handleLyricMouseDown(e) {
|
||||
// console.log(e)
|
||||
this.lyricEvent.isMsDown = true
|
||||
this.lyricEvent.msDownY = e.clientY
|
||||
this.lyricEvent.msDownScrollY = this.$refs.dom_lyric.scrollTop
|
||||
},
|
||||
handleMouseMsUp(e) {
|
||||
this.lyricEvent.isMsDown = false
|
||||
},
|
||||
handleMouseMsMove(e) {
|
||||
if (this.lyricEvent.isMsDown) {
|
||||
if (!this.lyricEvent.isStopScroll) this.lyricEvent.isStopScroll = true
|
||||
if (cancelScrollFn) {
|
||||
cancelScrollFn()
|
||||
cancelScrollFn = null
|
||||
}
|
||||
this.$refs.dom_lyric.scrollTop = this.lyricEvent.msDownScrollY + this.lyricEvent.msDownY - e.clientY
|
||||
this.startLyricScrollTimeout()
|
||||
}
|
||||
|
||||
// if (this.volumeEvent.isMsDown) {
|
||||
// let val = this.volumeEvent.msDownValue + (e.clientX - this.volumeEvent.msDownX) / 70
|
||||
// this.volume = val < 0 ? 0 : val > 1 ? 1 : val
|
||||
// if (this.audio) this.audio.volume = this.volume
|
||||
// }
|
||||
|
||||
// console.log(val)
|
||||
},
|
||||
startLyricScrollTimeout() {
|
||||
this.clearLyricScrollTimeout()
|
||||
this.lyricEvent.timeout = setTimeout(() => {
|
||||
this.lyricEvent.timeout = null
|
||||
this.lyricEvent.isStopScroll = false
|
||||
if (!this.isPlay) return
|
||||
this.handleScrollLrc()
|
||||
}, 3000)
|
||||
},
|
||||
handleWheel(event) {
|
||||
console.log(event.deltaY)
|
||||
if (!this.lyricEvent.isStopScroll) this.lyricEvent.isStopScroll = true
|
||||
if (cancelScrollFn) {
|
||||
cancelScrollFn()
|
||||
cancelScrollFn = null
|
||||
}
|
||||
this.$refs.dom_lyric.scrollTop = this.$refs.dom_lyric.scrollTop + event.deltaY
|
||||
this.startLyricScrollTimeout()
|
||||
},
|
||||
clearLyricScrollTimeout() {
|
||||
if (!this.lyricEvent.timeout) return
|
||||
clearTimeout(this.lyricEvent.timeout)
|
||||
this.lyricEvent.timeout = null
|
||||
},
|
||||
min() {
|
||||
window.eventHub.$emit(eventBaseName.min)
|
||||
},
|
||||
max() {
|
||||
window.eventHub.$emit(eventBaseName.max)
|
||||
},
|
||||
close() {
|
||||
window.eventHub.$emit(eventBaseName.close)
|
||||
},
|
||||
handleCopySelectText() {
|
||||
let str = window.getSelection().toString()
|
||||
str = str.trim()
|
||||
if (!str.length) return
|
||||
clipboardWriteText(str)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="less" module>
|
||||
@import '../../assets/styles/layout.less';
|
||||
|
||||
@control-btn-width: @height-toolbar * .26;
|
||||
|
||||
.container {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-color: @color-theme_2-background_1;
|
||||
z-index: 10;
|
||||
// -webkit-app-region: drag;
|
||||
overflow: hidden;
|
||||
border-radius: @radius-border;
|
||||
color: @color-theme_2-font;
|
||||
border-left: 12px solid @color-theme;
|
||||
-webkit-app-region: no-drag;
|
||||
|
||||
&.controlBtnLeft {
|
||||
.controBtn {
|
||||
left: 0;
|
||||
flex-direction: row-reverse;
|
||||
height: @height-toolbar * .7;
|
||||
button + button {
|
||||
margin-right: @control-btn-width / 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.controlBtnRight {
|
||||
.controBtn {
|
||||
right: @control-btn-width * .5;
|
||||
button + button {
|
||||
margin-left: @control-btn-width * 1.2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.bg {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-size: 110% 110%;
|
||||
filter: blur(60px);
|
||||
z-index: -1;
|
||||
}
|
||||
.bg2 {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: -1;
|
||||
background-color: rgba(255, 255, 255, .8);
|
||||
}
|
||||
|
||||
.header {
|
||||
position: relative;
|
||||
flex: 0 0 @height-toolbar;
|
||||
-webkit-app-region: drag;
|
||||
}
|
||||
|
||||
.controBtn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: @height-toolbar;
|
||||
-webkit-app-region: no-drag;
|
||||
padding: 0 @control-btn-width;
|
||||
&:hover {
|
||||
.controBtnIcon {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
position: relative;
|
||||
width: @control-btn-width;
|
||||
height: @control-btn-width;
|
||||
background: none;
|
||||
border: none;
|
||||
outline: none;
|
||||
padding: 1px;
|
||||
cursor: pointer;
|
||||
border-radius: 50%;
|
||||
color: @color-theme_2;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
&.hide {
|
||||
background-color: @color-hideBtn;
|
||||
}
|
||||
&.min {
|
||||
background-color: @color-minBtn;
|
||||
}
|
||||
&.max {
|
||||
background-color: @color-maxBtn;
|
||||
}
|
||||
&.close {
|
||||
background-color: @color-closeBtn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.controBtnIcon {
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.main {
|
||||
flex: auto;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
margin: 0 30px;
|
||||
position: relative;
|
||||
|
||||
&.showComment {
|
||||
.left {
|
||||
flex-basis: 18%;
|
||||
.description p {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
.right {
|
||||
flex-basis: 30%;
|
||||
.lyric {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
.comment {
|
||||
opacity: 1;
|
||||
transform: scaleX(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
.left {
|
||||
flex: 0 0 40%;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
align-items: center;
|
||||
padding: 13px;
|
||||
overflow: hidden;
|
||||
transition: flex-basis @transition-theme;
|
||||
}
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
justify-content: flex-start;
|
||||
max-width: 300px;
|
||||
|
||||
}
|
||||
.img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
min-width: 100%;
|
||||
box-shadow: 0 0 4px @color-theme-hover;
|
||||
border-radius: 6px;
|
||||
opacity: .8;
|
||||
// border: 5px solid @color-theme-hover;
|
||||
// border-radius: @radius-border;
|
||||
// border: 5px solid #fff;
|
||||
}
|
||||
.description {
|
||||
max-width: 300px;
|
||||
padding: 15px 0;
|
||||
overflow: hidden;
|
||||
p {
|
||||
line-height: 1.5;
|
||||
font-size: 14px;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
flex: 0 0 60%;
|
||||
// padding: 0 30px;
|
||||
position: relative;
|
||||
transition: flex-basis @transition-theme;
|
||||
|
||||
&:before {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
top: 0;
|
||||
left: 0;
|
||||
content: ' ';
|
||||
height: 100px;
|
||||
width: 100%;
|
||||
background-image: linear-gradient(0deg,rgba(255,255,255,0) 0%,@color-theme_2-background_1 95%);
|
||||
pointer-events: none;
|
||||
}
|
||||
&:after {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
content: ' ';
|
||||
height: 100px;
|
||||
width: 100%;
|
||||
background-image: linear-gradient(-180deg,rgba(255,255,255,0) 0%,@color-theme_2-background_1 95%);
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
.lyric {
|
||||
text-align: center;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
font-size: 16px;
|
||||
cursor: grab;
|
||||
&.draging {
|
||||
cursor: grabbing;
|
||||
}
|
||||
:global {
|
||||
.lrc-content {
|
||||
line-height: 1.2;
|
||||
margin: 16px 0;
|
||||
overflow-wrap: break-word;
|
||||
color: @color-player-detail-lyric;
|
||||
|
||||
.translation {
|
||||
transition: @transition-theme !important;
|
||||
transition-property: font-size, color;
|
||||
font-size: .9em;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.line {
|
||||
transition-property: font-size, color !important;
|
||||
background: none !important;
|
||||
-webkit-text-fill-color: unset;
|
||||
// -webkit-text-fill-color: none !important;
|
||||
}
|
||||
&.active {
|
||||
.line {
|
||||
color: @color-theme;
|
||||
}
|
||||
.translation {
|
||||
font-size: 1em;
|
||||
color: @color-theme;
|
||||
}
|
||||
span {
|
||||
// color: @color-theme;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
transition: @transition-theme !important;
|
||||
transition-property: font-size !important;
|
||||
font-size: 1em;
|
||||
background-repeat: no-repeat;
|
||||
background-color: rgba(77, 77, 77, 0.9);
|
||||
background-image: -webkit-linear-gradient(top, @color-theme, @color-theme);
|
||||
-webkit-text-fill-color: transparent;
|
||||
-webkit-background-clip: text;
|
||||
background-size: 0 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
// p {
|
||||
// padding: 8px 0;
|
||||
// line-height: 1.2;
|
||||
// overflow-wrap: break-word;
|
||||
// transition: @transition-theme !important;
|
||||
// transition-property: color, font-size;
|
||||
// }
|
||||
// .lrc-active {
|
||||
// color: @color-theme;
|
||||
// font-size: 1.2em;
|
||||
// }
|
||||
}
|
||||
.lyricSelectContent {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
// text-align: center;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
font-size: 16px;
|
||||
background-color: @color-theme_2-background_1;
|
||||
z-index: 10;
|
||||
color: @color-player-detail-lyric;
|
||||
|
||||
.lyricSelectline {
|
||||
padding: 8px 0;
|
||||
overflow-wrap: break-word;
|
||||
transition: @transition-theme !important;
|
||||
transition-property: color, font-size;
|
||||
line-height: 1.3;
|
||||
}
|
||||
.lyricSelectlineTransition {
|
||||
font-size: 14px;
|
||||
}
|
||||
.lrc-active {
|
||||
color: @color-theme;
|
||||
}
|
||||
}
|
||||
|
||||
.lyric-space {
|
||||
height: 70%;
|
||||
}
|
||||
|
||||
.comment {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
opacity: 1;
|
||||
margin-left: 10px;
|
||||
transform: scaleX(0);
|
||||
}
|
||||
|
||||
.footer {
|
||||
flex: 0 0 100px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.footerLeft {
|
||||
flex: auto;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
padding: 13px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.footerLeftControlBtns {
|
||||
color: @color-theme_2-font;
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.footerLeftControlBtn {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
opacity: .5;
|
||||
cursor: pointer;
|
||||
transition: opacity @transition-theme;
|
||||
|
||||
&:hover {
|
||||
opacity: .9;
|
||||
}
|
||||
|
||||
+.footerLeftControlBtn {
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: @color-theme;
|
||||
opacity: .8;
|
||||
}
|
||||
}
|
||||
.progress-container {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
padding: 3px 0;
|
||||
}
|
||||
.progress-content {
|
||||
position: relative;
|
||||
height: 15px;
|
||||
padding: 5px 0;
|
||||
width: 100%;
|
||||
}
|
||||
.progress {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
border-radius: 0.2rem;
|
||||
// overflow: hidden;
|
||||
transition: @transition-theme;
|
||||
transition-property: background-color;
|
||||
background-color: @color-player-progress;
|
||||
// background-color: #f5f5f5;
|
||||
position: relative;
|
||||
border-radius: @radius-progress-border;
|
||||
}
|
||||
.progress-mask {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
.progress-bar {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transform-origin: 0;
|
||||
border-top-right-radius: @radius-progress-border;
|
||||
border-bottom-right-radius: @radius-progress-border;
|
||||
}
|
||||
.progress-bar1 {
|
||||
background-color: @color-player-progress-bar1;
|
||||
}
|
||||
.progress-bar2 {
|
||||
background-color: @color-player-progress-bar2;
|
||||
box-shadow: 0 0 2px rgba(0, 0, 0, 0.3);
|
||||
border-top-right-radius: 20px;
|
||||
border-bottom-right-radius: 20px;
|
||||
}
|
||||
|
||||
.bar-transition {
|
||||
transition-property: transform;
|
||||
transition-timing-function: ease-out;
|
||||
transition-duration: 0.2s;
|
||||
}
|
||||
.time-label {
|
||||
width: 100%;
|
||||
height: 18px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
span {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
.play-control {
|
||||
flex: none;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
padding: 0 25px;
|
||||
color: @color-btn;
|
||||
}
|
||||
.play-btn {
|
||||
height: 40%;
|
||||
padding: 5px;
|
||||
cursor: pointer;
|
||||
flex: none;
|
||||
// transition: @transition-theme;
|
||||
// transition-property: color;
|
||||
color: @color-player-detail-play-btn;
|
||||
transition: opacity 0.2s ease;
|
||||
opacity: 1;
|
||||
cursor: pointer;
|
||||
|
||||
+.play-btn {
|
||||
margin-left: 10px;
|
||||
}
|
||||
svg {
|
||||
fill: currentColor;
|
||||
filter: drop-shadow(0 0 1px rgba(0, 0, 0, 0.2));
|
||||
}
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
&:active {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
each(@themes, {
|
||||
:global(#container.@{value}) {
|
||||
.container {
|
||||
border-left-color: ~'@{color-@{value}-theme}';
|
||||
background-color: ~'@{color-@{value}-theme_2-background_1}';
|
||||
// color: ~'@{color-@{value}-theme_2-font}';
|
||||
}
|
||||
.right {
|
||||
&:before {
|
||||
background-image: linear-gradient(0deg,rgba(255,255,255,0) 0%,~'@{color-@{value}-theme_2-background_1}' 95%);
|
||||
}
|
||||
&:after {
|
||||
background-image: linear-gradient(-180deg,rgba(255,255,255,0) 0%,~'@{color-@{value}-theme_2-background_1}' 95%);
|
||||
}
|
||||
}
|
||||
.controBtn {
|
||||
button {
|
||||
color: ~'@{color-@{value}-theme_2}';
|
||||
// &.hide:after {
|
||||
// background-color: ~'@{color-@{value}-hideBtn}';
|
||||
// }
|
||||
&.hide {
|
||||
background-color: ~'@{color-@{value}-hideBtn}';
|
||||
}
|
||||
&.min {
|
||||
background-color: ~'@{color-@{value}-minBtn}';
|
||||
}
|
||||
&.max {
|
||||
background-color: ~'@{color-@{value}-maxBtn}';
|
||||
}
|
||||
&.close {
|
||||
background-color: ~'@{color-@{value}-closeBtn}';
|
||||
}
|
||||
}
|
||||
}
|
||||
.img {
|
||||
box-shadow: 0 0 4px ~'@{color-@{value}-theme-hover}';
|
||||
// border-color: ~'@{color-@{value}-theme-hover}';
|
||||
}
|
||||
.lyric {
|
||||
:global {
|
||||
.lrc-content {
|
||||
color: ~'@{color-@{value}-player-detail-lyric}';
|
||||
|
||||
&.active {
|
||||
.translation {
|
||||
color: ~'@{color-@{value}-player-detail-lyric-active}';
|
||||
}
|
||||
.line {
|
||||
color: ~'@{color-@{value}-player-detail-lyric-active}';
|
||||
}
|
||||
}
|
||||
span {
|
||||
background-color: ~'@{color-@{value}-player-detail-lyric}';
|
||||
background-image: -webkit-linear-gradient(top, ~'@{color-@{value}-player-detail-lyric-active}', ~'@{color-@{value}-player-detail-lyric-active}');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// .lrc-active {
|
||||
// color: ~'@{color-@{value}-theme}';
|
||||
// }
|
||||
.lyricSelectContent {
|
||||
background-color: ~'@{color-@{value}-theme_2-background_1}';
|
||||
color: ~'@{color-@{value}-player-detail-lyric}';
|
||||
.lrc-active {
|
||||
color: ~'@{color-@{value}-theme}';
|
||||
}
|
||||
}
|
||||
.footerLeftControlBtns {
|
||||
color: ~'@{color-@{value}-theme_2-font}';
|
||||
}
|
||||
.footerLeftControlBtn {
|
||||
&.active {
|
||||
color: ~'@{color-@{value}-theme}';
|
||||
}
|
||||
}
|
||||
.progress {
|
||||
background-color: ~'@{color-@{value}-player-progress}';
|
||||
}
|
||||
.progress-bar1 {
|
||||
background-color: ~'@{color-@{value}-player-progress-bar1}';
|
||||
}
|
||||
.progress-bar2 {
|
||||
background-color: ~'@{color-@{value}-player-progress-bar2}';
|
||||
}
|
||||
.play-btn {
|
||||
color: ~'@{color-@{value}-player-detail-play-btn}';
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,159 @@
|
||||
<template lang="pug">
|
||||
material-modal(:show="sync.isShowSyncMode" @close="handleClose(false)" :bgClose="false" :close-btn="false")
|
||||
main(:class="$style.main")
|
||||
h2 {{$t('sync__title', { name: sync.deviceName })}}
|
||||
div.scroll(:class="$style.content")
|
||||
dl(:class="$style.btnGroup")
|
||||
dt(:class="$style.label") {{$t('sync__merge_label')}}
|
||||
dd(:class="$style.btns")
|
||||
base-btn(:class="$style.btn" @click="handleSelectMode('merge_local_remote')") {{$t('sync__merge_btn_local_remote')}}
|
||||
base-btn(:class="$style.btn" @click="handleSelectMode('merge_remote_local')") {{$t('sync__merge_btn_remote_local')}}
|
||||
dl(:class="$style.btnGroup")
|
||||
dt(:class="$style.label") {{$t('sync__overwrite_label')}}
|
||||
dd(:class="$style.btns")
|
||||
base-btn(:class="$style.btn" @click="handleSelectMode('overwrite_local_remote')") {{$t('sync__overwrite_btn_local_remote')}}
|
||||
base-btn(:class="$style.btn" @click="handleSelectMode('overwrite_remote_local')") {{$t('sync__overwrite_btn_remote_local')}}
|
||||
dd(style="font-size: 14px; margin-top: 5px;")
|
||||
base-checkbox(id="sync_mode_modal_isOverwrite" v-model="isOverwrite" :label="$t('sync__overwrite')")
|
||||
|
||||
dl(:class="$style.btnGroup")
|
||||
dt(:class="$style.label") {{$t('sync__other_label')}}
|
||||
dd(:class="$style.btns")
|
||||
base-btn(:class="$style.btn" @click="handleSelectMode('none')") {{$t('sync__overwrite_btn_none')}}
|
||||
base-btn(:class="$style.btn" @click="handleSelectMode('cancel')") {{$t('sync__overwrite_btn_cancel')}}
|
||||
dl(:class="$style.btnGroup")
|
||||
dd
|
||||
section(:class="$style.tipGroup")
|
||||
h3(:class="$style.title") {{$t('sync__merge_tip')}}
|
||||
p(:class="$style.tip") {{$t('sync__merge_tip_desc')}}
|
||||
section(:class="$style.tipGroup")
|
||||
h3(:class="$style.title") {{$t('sync__overwrite_tip')}}
|
||||
p(:class="$style.tip") {{$t('sync__overwrite_tip_desc')}}
|
||||
section(:class="$style.tipGroup")
|
||||
h3(:class="$style.title") {{$t('sync__other_tip')}}
|
||||
p(:class="$style.tip") {{$t('sync__other_tip_desc')}}
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { sync as eventSyncName } from '@renderer/event/names'
|
||||
import { sync } from '@renderer/core/share'
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
return {
|
||||
sync,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isOverwrite: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
||||
},
|
||||
methods: {
|
||||
handleSelectMode(mode) {
|
||||
if (mode.startsWith('overwrite') && this.isOverwrite) mode += '_full'
|
||||
window.eventHub.emit(eventSyncName.send_sync_list, {
|
||||
action: 'selectMode',
|
||||
data: mode,
|
||||
})
|
||||
this.handleClose()
|
||||
},
|
||||
handleClose() {
|
||||
sync.isShowSyncMode = false
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="less" module>
|
||||
@import '@renderer/assets/styles/layout.less';
|
||||
|
||||
.main {
|
||||
padding: 15px;
|
||||
max-width: 700px;
|
||||
min-width: 200px;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
justify-content: center;
|
||||
h2 {
|
||||
font-size: 16px;
|
||||
color: @color-theme_2-font;
|
||||
line-height: 1.3;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: auto;
|
||||
padding: 15px 0 5px;
|
||||
padding-right: 5px;
|
||||
.btnGroup + .btnGroup {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.label {
|
||||
color: @color-theme_2-font-label;
|
||||
font-size: 14px;
|
||||
line-height: 2;
|
||||
}
|
||||
.desc {
|
||||
line-height: 1.5;
|
||||
font-size: 14px;
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
.tipGroup {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
font-size: 12px;
|
||||
|
||||
+ .tipGroup {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.title {
|
||||
white-space: nowrap;
|
||||
font-weight: bold;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.tip {
|
||||
line-height: 1.3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btns {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.btn {
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
+.btn {
|
||||
margin-left: 15px;
|
||||
}
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
each(@themes, {
|
||||
:global(#root.@{value}) {
|
||||
.main {
|
||||
h2 {
|
||||
color: ~'@{color-@{value}-theme_2-font}';
|
||||
}
|
||||
}
|
||||
.name {
|
||||
color: ~'@{color-@{value}-theme}';
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
</style>
|
||||
@@ -1,242 +0,0 @@
|
||||
<template lang="pug">
|
||||
div(:class="[$style.toolbar, setting.controlBtnPosition == 'left' ? $style.controlBtnLeft : $style.controlBtnRight]")
|
||||
//- img(v-if="icon")
|
||||
//- h1 {{title}}
|
||||
material-search-input(:class="$style.input"
|
||||
@event="handleEvent" :list="tipList" :visibleList="visibleList"
|
||||
v-model="searchText")
|
||||
|
||||
div(:class="$style.logo" v-if="setting.controlBtnPosition == 'left'") L X
|
||||
div(:class="$style.control" v-else)
|
||||
button(type="button" :class="$style.min" :tips="$t('core.toolbar.min')" @click="min")
|
||||
svg(:class="$style.icon" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='100%' viewBox='0 0 24 24' space='preserve')
|
||||
use(xlink:href='#icon-window-minimize')
|
||||
|
||||
//- button(type="button" :class="$style.max" @click="max")
|
||||
button(type="button" :class="$style.close" :tips="$t('core.toolbar.close')" @click="close")
|
||||
svg(:class="$style.icon" version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' width='100%' viewBox='0 0 24 24' space='preserve')
|
||||
use(xlink:href='#icon-window-close')
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapMutations } from 'vuex'
|
||||
import music from '../../utils/music'
|
||||
import { debounce } from '../../utils'
|
||||
import { base as eventBaseName } from '../../event/names'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
searchText: '',
|
||||
visibleList: false,
|
||||
tipList: [],
|
||||
tipSearch: null,
|
||||
isFocused: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['route', 'setting']),
|
||||
...mapGetters('search', {
|
||||
storeSearchText: 'searchText',
|
||||
}),
|
||||
source() {
|
||||
return this.setting.search.tempSearchSource
|
||||
},
|
||||
isAutoClearSearchInput() {
|
||||
return this.setting.odc.isAutoClearSearchInput
|
||||
},
|
||||
isAutoClearSearchList() {
|
||||
return this.setting.odc.isAutoClearSearchList
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
route(n) {
|
||||
if (n.name != 'search') {
|
||||
if (this.isAutoClearSearchInput && this.searchText) this.searchText = ''
|
||||
if (this.isAutoClearSearchList) this.clearSearchList()
|
||||
}
|
||||
},
|
||||
storeSearchText(n) {
|
||||
if (n !== this.searchText) this.searchText = n
|
||||
},
|
||||
searchText(n) {
|
||||
this.handleTipSearch()
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.tipSearch = debounce(() => {
|
||||
if (this.searchText === '') {
|
||||
this.tipList.splice(0, this.tipList.length)
|
||||
music[this.source].tempSearch.cancelTempSearch()
|
||||
return
|
||||
}
|
||||
music[this.source].tempSearch.search(this.searchText).then(list => {
|
||||
this.tipList = list
|
||||
}).catch(() => {})
|
||||
}, 50)
|
||||
},
|
||||
methods: {
|
||||
...mapMutations('search', {
|
||||
clearSearchList: 'clearList',
|
||||
}),
|
||||
handleEvent({ action, data }) {
|
||||
switch (action) {
|
||||
case 'focus':
|
||||
this.isFocused = true
|
||||
if (!this.visibleList) this.visibleList = true
|
||||
if (this.searchText) this.handleTipSearch()
|
||||
break
|
||||
case 'blur':
|
||||
this.isFocused = false
|
||||
setTimeout(() => {
|
||||
if (this.visibleList) this.visibleList = false
|
||||
}, 50)
|
||||
break
|
||||
case 'submit':
|
||||
this.handleSearch()
|
||||
break
|
||||
case 'listClick':
|
||||
this.searchText = this.tipList[data]
|
||||
this.$nextTick(() => {
|
||||
this.handleSearch()
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
handleTipSearch() {
|
||||
if (!this.visibleList && this.isFocused) this.visibleList = true
|
||||
this.tipSearch()
|
||||
},
|
||||
|
||||
handleSearch() {
|
||||
if (this.visibleList) this.visibleList = false
|
||||
setTimeout(() => {
|
||||
this.$router.push({
|
||||
path: 'search',
|
||||
query: {
|
||||
text: this.searchText,
|
||||
},
|
||||
}).catch(_ => _)
|
||||
}, 200)
|
||||
},
|
||||
|
||||
min() {
|
||||
window.eventHub.$emit(eventBaseName.min)
|
||||
},
|
||||
max() {
|
||||
window.eventHub.$emit(eventBaseName.max)
|
||||
},
|
||||
close() {
|
||||
window.eventHub.$emit(eventBaseName.close)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="less" module>
|
||||
@import '../../assets/styles/layout.less';
|
||||
|
||||
@control-btn-width: @height-toolbar * .26;
|
||||
|
||||
.toolbar {
|
||||
display: flex;
|
||||
height: @height-toolbar;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding-left: 15px;
|
||||
-webkit-app-region: drag;
|
||||
z-index: 2;
|
||||
|
||||
&.controlBtnLeft {
|
||||
.control {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
&.controlBtnRight {
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
.logo {
|
||||
box-sizing: border-box;
|
||||
padding: 0 @height-toolbar * .4;
|
||||
height: @height-toolbar;
|
||||
color: @color-theme;
|
||||
flex: none;
|
||||
text-align: center;
|
||||
line-height: @height-toolbar;
|
||||
font-weight: bold;
|
||||
// -webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
.control {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
left: 15px;
|
||||
-webkit-app-region: no-drag;
|
||||
padding: 0 @control-btn-width * 1.5;
|
||||
&:hover {
|
||||
.icon {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
display: flex;
|
||||
position: relative;
|
||||
width: @control-btn-width;
|
||||
height: @control-btn-width;
|
||||
background: none;
|
||||
border: none;
|
||||
outline: none;
|
||||
padding: 1px;
|
||||
cursor: pointer;
|
||||
border-radius: 50%;
|
||||
color: @color-theme_2;
|
||||
|
||||
+ button {
|
||||
margin-left: @control-btn-width * 1.2;
|
||||
}
|
||||
|
||||
&.min {
|
||||
background-color: @color-minBtn;
|
||||
}
|
||||
&.max {
|
||||
background-color: @color-maxBtn;
|
||||
}
|
||||
&.close {
|
||||
background-color: @color-closeBtn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
|
||||
each(@themes, {
|
||||
:global(#container.@{value}) {
|
||||
.control {
|
||||
button {
|
||||
color: ~'@{color-@{value}-theme_2}';
|
||||
|
||||
&.min {
|
||||
background-color: ~'@{color-@{value}-minBtn}';
|
||||
}
|
||||
&.max {
|
||||
background-color: ~'@{color-@{value}-maxBtn}';
|
||||
}
|
||||
&.close {
|
||||
background-color: ~'@{color-@{value}-closeBtn}';
|
||||
}
|
||||
}
|
||||
}
|
||||
.logo {
|
||||
color: ~'@{color-@{value}-theme}';
|
||||
}
|
||||
}
|
||||
})
|
||||
</style>
|
||||
@@ -0,0 +1,108 @@
|
||||
<template>
|
||||
<div :class="$style.control">
|
||||
<button type="button" :class="[$style.btn, $style.min]" :tips="$t('min')" @click="min">
|
||||
<svg :class="$style.controlBtniIcon" version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" width="100%" viewBox="0 0 24 24" space="preserve">
|
||||
<use xlink:href="#icon-window-minimize"></use>
|
||||
</svg>
|
||||
</button>
|
||||
<button type="button" :class="[$style.btn, $style.close]" :tips="$t('close')" @click="close">
|
||||
<svg :class="$style.controlBtniIcon" version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" width="100%" viewBox="0 0 24 24" space="preserve">
|
||||
<use xlink:href="#icon-window-close"></use>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { base as eventBaseName } from '@renderer/event/names'
|
||||
// import { getRandom } from '../../utils'
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
return {
|
||||
min() {
|
||||
window.eventHub.emit(eventBaseName.min)
|
||||
},
|
||||
max() {
|
||||
window.eventHub.emit(eventBaseName.max)
|
||||
},
|
||||
close() {
|
||||
window.eventHub.emit(eventBaseName.close)
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
<style lang="less" module>
|
||||
@import '@renderer/assets/styles/layout.less';
|
||||
|
||||
@control-btn-width: @height-toolbar * .26;
|
||||
|
||||
.control {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
left: 15px;
|
||||
-webkit-app-region: no-drag;
|
||||
padding: 0 @control-btn-width * 1.5;
|
||||
&:hover {
|
||||
.controlBtniIcon {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: flex;
|
||||
position: relative;
|
||||
width: @control-btn-width;
|
||||
height: @control-btn-width;
|
||||
background: none;
|
||||
border: none;
|
||||
outline: none;
|
||||
padding: 1px;
|
||||
cursor: pointer;
|
||||
border-radius: 50%;
|
||||
color: @color-theme_2;
|
||||
|
||||
+ .btn {
|
||||
margin-left: @control-btn-width * 1.2;
|
||||
}
|
||||
|
||||
&.min {
|
||||
background-color: @color-minBtn;
|
||||
}
|
||||
&.max {
|
||||
background-color: @color-maxBtn;
|
||||
}
|
||||
&.close {
|
||||
background-color: @color-closeBtn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.controlBtniIcon {
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
each(@themes, {
|
||||
:global(#root.@{value}) {
|
||||
.btn {
|
||||
color: ~'@{color-@{value}-theme_2}';
|
||||
|
||||
&.min {
|
||||
background-color: ~'@{color-@{value}-minBtn}';
|
||||
}
|
||||
&.max {
|
||||
background-color: ~'@{color-@{value}-maxBtn}';
|
||||
}
|
||||
&.close {
|
||||
background-color: ~'@{color-@{value}-closeBtn}';
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</style>
|
||||
@@ -0,0 +1,109 @@
|
||||
<template>
|
||||
<material-search-input @event="handleEvent" :list="tipList" :visibleList="visibleList" v-model="searchText" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import music from '@renderer/utils/music'
|
||||
import { debounce } from '@renderer/utils'
|
||||
import {
|
||||
ref,
|
||||
useRoute,
|
||||
useGetter,
|
||||
watch,
|
||||
useRefGetter,
|
||||
useRouter,
|
||||
nextTick,
|
||||
useCommit,
|
||||
} from '@renderer/utils/vueTools'
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const searchText = ref('')
|
||||
const visibleList = ref(false)
|
||||
const tipList = ref([])
|
||||
let isFocused = false
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
const setting = useGetter('setting')
|
||||
|
||||
const clearSearchList = useCommit('search', 'clearList')
|
||||
|
||||
watch(() => route.name, (newValue, oldValue) => {
|
||||
if (newValue.name != 'search') {
|
||||
if (setting.odc.isAutoClearSearchInput && searchText.value) searchText.value = ''
|
||||
if (setting.odc.isAutoClearSearchList) clearSearchList()
|
||||
}
|
||||
})
|
||||
|
||||
const storeSearchText = useRefGetter('search', 'searchText')
|
||||
watch(storeSearchText, (newValue, oldValue) => {
|
||||
searchText.value = newValue
|
||||
if (newValue !== searchText.value) searchText.value = newValue
|
||||
})
|
||||
watch(searchText, () => {
|
||||
handleTipSearch()
|
||||
})
|
||||
|
||||
|
||||
const tipSearch = debounce(() => {
|
||||
if (searchText.value === '') {
|
||||
tipList.value = []
|
||||
music[setting.search.tempSearchSource].tempSearch.cancelTempSearch()
|
||||
return
|
||||
}
|
||||
music[setting.search.tempSearchSource].tempSearch.search(searchText.value).then(list => {
|
||||
tipList.value = list
|
||||
}).catch(() => {})
|
||||
}, 50)
|
||||
|
||||
const handleTipSearch = () => {
|
||||
if (!visibleList.value && isFocused) visibleList.value = true
|
||||
tipSearch()
|
||||
}
|
||||
|
||||
const handleSearch = () => {
|
||||
if (visibleList.value) visibleList.value = false
|
||||
setTimeout(() => {
|
||||
router.push({
|
||||
path: 'search',
|
||||
query: {
|
||||
text: searchText.value,
|
||||
},
|
||||
}).catch(_ => _)
|
||||
}, 200)
|
||||
}
|
||||
|
||||
const handleEvent = ({ action, data }) => {
|
||||
switch (action) {
|
||||
case 'focus':
|
||||
isFocused = true
|
||||
if (!visibleList.value) visibleList.value = true
|
||||
if (searchText.value) handleTipSearch()
|
||||
break
|
||||
case 'blur':
|
||||
isFocused = false
|
||||
setTimeout(() => {
|
||||
if (visibleList.value) visibleList.value = false
|
||||
}, 50)
|
||||
break
|
||||
case 'submit':
|
||||
handleSearch()
|
||||
break
|
||||
case 'listClick':
|
||||
searchText.value = tipList[data]
|
||||
nextTick(handleSearch)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
searchText,
|
||||
visibleList,
|
||||
tipList,
|
||||
handleEvent,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
@@ -0,0 +1,65 @@
|
||||
<template>
|
||||
<div :class="[$style.toolbar, setting.controlBtnPosition == 'left' ? $style.controlBtnLeft : $style.controlBtnRight]">
|
||||
<SearchInput />
|
||||
<div :class="$style.logo" v-if="setting.controlBtnPosition == 'left'">L X</div>
|
||||
<ControlBtns v-else />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
import ControlBtns from './ControlBtns'
|
||||
import SearchInput from './SearchInput'
|
||||
|
||||
export default {
|
||||
components: { SearchInput, ControlBtns },
|
||||
computed: {
|
||||
...mapGetters(['setting']),
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="less" module>
|
||||
@import '@renderer/assets/styles/layout.less';
|
||||
|
||||
.toolbar {
|
||||
display: flex;
|
||||
height: @height-toolbar;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding-left: 15px;
|
||||
-webkit-app-region: drag;
|
||||
z-index: 2;
|
||||
|
||||
&.controlBtnLeft {
|
||||
.control {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
&.controlBtnRight {
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
.logo {
|
||||
box-sizing: border-box;
|
||||
padding: 0 @height-toolbar * .4;
|
||||
height: @height-toolbar;
|
||||
color: @color-theme;
|
||||
flex: none;
|
||||
text-align: center;
|
||||
line-height: @height-toolbar;
|
||||
font-weight: bold;
|
||||
// -webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
each(@themes, {
|
||||
:global(#root.@{value}) {
|
||||
.logo {
|
||||
color: ~'@{color-@{value}-theme}';
|
||||
}
|
||||
}
|
||||
})
|
||||
</style>
|
||||
@@ -0,0 +1,313 @@
|
||||
<template lang="pug">
|
||||
material-modal(:show="versionInfo.showModal" @close="handleClose")
|
||||
main(:class="$style.main" v-if="versionInfo.isDownloaded")
|
||||
h2 🚀程序更新🚀
|
||||
|
||||
div.scroll.select(:class="$style.info")
|
||||
div(:class="$style.current")
|
||||
h3 最新版本:{{versionInfo.newVersion?.version}}
|
||||
h3 当前版本:{{versionInfo.version}}
|
||||
h3 版本变化:
|
||||
pre(:class="$style.desc" v-text="versionInfo.newVersion?.desc")
|
||||
div(:class="[$style.history, $style.desc]" v-if="history.length")
|
||||
h3 历史版本:
|
||||
div(:class="$style.item" v-for="ver in history")
|
||||
h4 v{{ver.version}}
|
||||
pre(v-text="ver.desc")
|
||||
div(:class="$style.footer")
|
||||
div(:class="$style.desc")
|
||||
p 新版本已下载完毕,
|
||||
p
|
||||
| 你可以选择
|
||||
strong 立即重启更新
|
||||
| 或稍后
|
||||
strong 关闭程序时
|
||||
| 自动更新~
|
||||
base-btn(:class="$style.btn" @click.onec="handleRestartClick") 立即重启更新
|
||||
main(:class="$style.main" v-else-if="versionInfo.isError && !versionInfo.isUnknow && versionInfo.newVersion?.version != versionInfo.version")
|
||||
h2 ❌ 版本更新出错 ❌
|
||||
|
||||
div.scroll.select(:class="$style.info")
|
||||
div(:class="$style.current")
|
||||
h3 最新版本:{{versionInfo.newVersion?.version}}
|
||||
h3 当前版本:{{versionInfo.version}}
|
||||
h3 版本变化:
|
||||
pre(:class="$style.desc" v-text="versionInfo.newVersion?.desc")
|
||||
div(:class="[$style.history, $style.desc]" v-if="history.length")
|
||||
h3 历史版本:
|
||||
div(:class="$style.item" v-for="ver in history")
|
||||
h4 v{{ver.version}}
|
||||
pre(v-text="ver.desc")
|
||||
|
||||
div(:class="$style.footer")
|
||||
div(:class="$style.desc")
|
||||
p 发现有新版本啦,但是自动更新功能出问题了,
|
||||
p
|
||||
| 你可以去
|
||||
strong.hover.underline(@click="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop/releases')" tips="点击打开") 软件发布页
|
||||
| 或
|
||||
strong.hover.underline(@click="handleOpenUrl('https://www.lanzoui.com/b0bf2cfa/')" tips="点击打开") 网盘
|
||||
| (密码:
|
||||
strong.hover(@click="handleCopy('glqw')" tips="点击复制") glqw
|
||||
| ) 下载新版本,
|
||||
p
|
||||
| 国内Windows/MAC用户推荐到
|
||||
strong 网盘
|
||||
| 下载。
|
||||
base-btn(:class="$style.btn" @click.onec="handleIgnoreClick") {{ isIgnored ? '恢复当前版本的更新失败提醒' : '忽略当前版本的更新失败提醒'}}
|
||||
main(:class="$style.main" v-else-if="versionInfo.isDownloading && versionInfo.isTimeOut && !versionInfo.isUnknow")
|
||||
h2 ❗️ 新版本下载超时 ❗️
|
||||
div(:class="$style.desc")
|
||||
p 你当前所在网络访问GitHub较慢,导致新版本下载超时(已经下了半个钟了😳),你仍可选择继续等,但墙裂建议手动更新版本!
|
||||
p
|
||||
| 你可以去
|
||||
base-btn(min @click="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop/releases')" tips="点击打开") 软件发布页
|
||||
| 或
|
||||
base-btn(min @click="handleOpenUrl('https://www.lanzoui.com/b0bf2cfa/')" tips="点击打开") 网盘
|
||||
| (密码:
|
||||
strong.hover(@click="handleCopy('glqw')" tips="点击复制") glqw
|
||||
| )下载新版本,
|
||||
p
|
||||
| 国内Windows/MAC用户推荐到
|
||||
strong 网盘
|
||||
| 下载。
|
||||
p 当前下载进度:{{progress}}
|
||||
main(:class="$style.main" v-else-if="versionInfo.isUnknow")
|
||||
h2 ❓ 获取最新版本信息失败 ❓
|
||||
|
||||
div.scroll.select(:class="$style.info")
|
||||
div(:class="$style.current")
|
||||
h3 当前版本:{{versionInfo.version}}
|
||||
div(:class="$style.desc")
|
||||
p 更新信息获取失败,可能是无法访问Github导致的,请手动检查更新!
|
||||
p
|
||||
| 检查方法:打开
|
||||
base-btn(min @click="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop/releases')" tips="点击打开") 软件发布页
|
||||
| 或
|
||||
base-btn(min @click="handleOpenUrl('https://www.lanzoui.com/b0bf2cfa/')" tips="点击打开") 网盘
|
||||
| (密码:
|
||||
strong.hover(@click="handleCopy('glqw')" tips="点击复制") glqw
|
||||
| )查看它们的
|
||||
strong 版本号
|
||||
| 与当前版本({{versionInfo.version}})对比是否一样,
|
||||
p 若一样则不必理会该弹窗,直接关闭即可,否则请手动下载新版本更新。
|
||||
main(:class="$style.main" v-else)
|
||||
h2 🌟发现新版本🌟
|
||||
|
||||
div.scroll.select(:class="$style.info")
|
||||
div(:class="$style.current")
|
||||
h3 最新版本:{{versionInfo.newVersion?.version}}
|
||||
h3 当前版本:{{versionInfo.version}}
|
||||
h3 版本变化:
|
||||
pre(:class="$style.desc" v-text="versionInfo.newVersion?.desc")
|
||||
div(:class="[$style.history, $style.desc]" v-if="history.length")
|
||||
h3 历史版本:
|
||||
div(:class="$style.item" v-for="ver in history")
|
||||
h4 v{{ver.version}}
|
||||
pre(v-text="ver.desc")
|
||||
|
||||
div(:class="$style.footer")
|
||||
div(:class="$style.desc")
|
||||
p 发现有新版本啦,正在努力更新中,若下载太慢可以手动更新哦~
|
||||
p
|
||||
| 你也可以关闭本弹窗继续使用软件,还可在
|
||||
strong 设置-软件更新
|
||||
| 重新打开本弹窗。
|
||||
p
|
||||
| 手动更新可以去
|
||||
strong.hover.underline(@click="handleOpenUrl('https://github.com/lyswhut/lx-music-desktop/releases')" tips="点击打开") 软件发布页
|
||||
| 或
|
||||
strong.hover.underline(@click="handleOpenUrl('https://www.lanzoui.com/b0bf2cfa/')" tips="点击打开") 网盘
|
||||
| (密码:
|
||||
strong.hover(@click="handleCopy('glqw')" tips="点击复制") glqw
|
||||
| ) 下载,
|
||||
p 国内Windows/MAC用户推荐到网盘下载。
|
||||
p 当前下载进度:{{progress}}
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapMutations } from 'vuex'
|
||||
import { rendererSend, NAMES } from '@common/ipc'
|
||||
import { compareVer, openUrl, clipboardWriteText, sizeFormate } from '@renderer/utils'
|
||||
import { versionInfo } from '@renderer/core/share'
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
return {
|
||||
versionInfo,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['setting']),
|
||||
history() {
|
||||
if (!this.versionInfo.newVersion || !this.versionInfo.newVersion?.history) return []
|
||||
let arr = []
|
||||
let currentVer = this.versionInfo.version
|
||||
this.versionInfo.newVersion?.history.forEach(ver => {
|
||||
if (compareVer(currentVer, ver.version) < 0) arr.push(ver)
|
||||
})
|
||||
|
||||
return arr
|
||||
},
|
||||
progress() {
|
||||
return this.versionInfo.downloadProgress
|
||||
? `${this.versionInfo.downloadProgress.percent.toFixed(2)}% - ${sizeFormate(this.versionInfo.downloadProgress.transferred)}/${sizeFormate(this.versionInfo.downloadProgress.total)} - ${sizeFormate(this.versionInfo.downloadProgress.bytesPerSecond)}/s`
|
||||
: '处理更新中...'
|
||||
},
|
||||
isIgnored() {
|
||||
return this.setting.ignoreVersion == this.versionInfo.newVersion?.version
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['setIgnoreVersion']),
|
||||
handleClose() {
|
||||
versionInfo.showModal = false
|
||||
},
|
||||
handleOpenUrl(url) {
|
||||
openUrl(url)
|
||||
},
|
||||
handleRestartClick(event) {
|
||||
this.handleClose()
|
||||
event.target.disabled = true
|
||||
rendererSend(NAMES.mainWindow.quit_update)
|
||||
},
|
||||
handleCopy(text) {
|
||||
clipboardWriteText(text)
|
||||
},
|
||||
handleIgnoreClick() {
|
||||
this.setIgnoreVersion(this.isIgnored ? null : this.versionInfo.newVersion?.version)
|
||||
this.handleClose()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="less" module>
|
||||
@import '@renderer/assets/styles/layout.less';
|
||||
|
||||
.main {
|
||||
position: relative;
|
||||
padding: 15px;
|
||||
max-width: 450px;
|
||||
min-width: 300px;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
// overflow-y: auto;
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
h2 {
|
||||
flex: 0 0 none;
|
||||
font-size: 16px;
|
||||
color: @color-theme_2-font;
|
||||
line-height: 1.3;
|
||||
text-align: center;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
h3 {
|
||||
font-size: 14px;
|
||||
line-height: 1.3;
|
||||
}
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
text-align: justify;
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.info {
|
||||
flex: 1 1 auto;
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
overflow-y: auto;
|
||||
height: 100%;
|
||||
padding-right: 5px;
|
||||
}
|
||||
.current {
|
||||
> p {
|
||||
padding-left: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.desc {
|
||||
h3, h4 {
|
||||
font-weight: bold;
|
||||
}
|
||||
h3 {
|
||||
padding: 5px 0 3px;
|
||||
}
|
||||
ul {
|
||||
list-style: initial;
|
||||
padding-inline-start: 30px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
|
||||
.history {
|
||||
h3 {
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
.item {
|
||||
h3 {
|
||||
padding: 5px 0 3px;
|
||||
}
|
||||
padding: 0 15px;
|
||||
+ .item {
|
||||
padding-top: 15px;
|
||||
}
|
||||
h4 {
|
||||
font-weight: 700;
|
||||
}
|
||||
> p {
|
||||
padding-left: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
.footer {
|
||||
flex: 0 0 none;
|
||||
.desc {
|
||||
padding-top: 10px;
|
||||
font-size: 12px;
|
||||
color: @color-theme;
|
||||
line-height: 1.25;
|
||||
|
||||
p {
|
||||
font-size: 12px;
|
||||
color: @color-theme;
|
||||
line-height: 1.25;
|
||||
}
|
||||
}
|
||||
}
|
||||
.btn {
|
||||
margin-top: 10px;
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
each(@themes, {
|
||||
:global(#root.@{value}) {
|
||||
.main {
|
||||
h2 {
|
||||
color: ~'@{color-@{value}-theme_2-font}';
|
||||
}
|
||||
}
|
||||
.footer {
|
||||
.desc {
|
||||
color: ~'@{color-@{value}-theme}';
|
||||
p {
|
||||
color: ~'@{color-@{value}-theme}';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
</style>
|
||||
@@ -1,15 +1,31 @@
|
||||
<template lang="pug">
|
||||
div(:class="$style.view")
|
||||
transition(enter-active-class="animated-fast fadeIn"
|
||||
leave-active-class="animated-fast fadeOut")
|
||||
router-view
|
||||
//- core-title-bar
|
||||
//- router-view
|
||||
<template>
|
||||
<div :class="$style.view">
|
||||
<router-view v-slot="{ Component }" v-if="mounted">
|
||||
<transition enter-active-class="animated-fast fadeIn" leave-active-class="animated-fast fadeOut">
|
||||
<component :is="Component" />
|
||||
</transition>
|
||||
</router-view>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { ref, onMounted } from '@renderer/utils/vueTools'
|
||||
export default {
|
||||
setup() {
|
||||
const mounted = ref(false)
|
||||
|
||||
onMounted(() => {
|
||||
mounted.value = true
|
||||
})
|
||||
|
||||
return {
|
||||
mounted,
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" module>
|
||||
@import '../../assets/styles/layout.less';
|
||||
@import '@renderer/assets/styles/layout.less';
|
||||
|
||||
.view {
|
||||
position: relative;
|
||||
|
||||
Reference in New Issue
Block a user