初始提交

This commit is contained in:
lyswhut
2019-08-16 17:27:23 +08:00
parent 4dc34a48f4
commit 14f7bd10a3
112 changed files with 24294 additions and 2 deletions
+59
View File
@@ -0,0 +1,59 @@
<template lang="pug">
button(:class="[$style.btn, min ? $style.min : '']" @click="$emit('click', $event)")
slot
</template>
<script>
export default {
props: {
min: {
type: Boolean,
},
},
}
</script>
<style lang="less" module>
@import '../../assets/styles/layout.less';
.btn {
display: inline-block;
border: none;
border-radius: 3px;
cursor: pointer;
padding: 8px 15px;
color: @color-btn;
outline: none;
transition: background-color 0.2s ease;
background-color: @color-btn-background;
&:hover {
background-color: @color-theme_2-hover;
}
&:active {
background-color: @color-theme_2-active;
}
}
.min {
padding: 3px 8px;
font-size: 12px;
}
each(@themes, {
:global(#container.@{value}) {
.btn {
color: ~'@{color-@{value}-btn}';
background-color: ~'@{color-@{value}-btn-background}';
&:hover {
background-color: ~'@{color-@{value}-theme_2-hover}';
}
&:active {
background-color: ~'@{color-@{value}-theme_2-active}';
}
}
}
})
</style>
@@ -0,0 +1,160 @@
<template lang="pug">
div(:class="$style.checkbox")
input(:type="need ? 'radio' : 'checkbox'" :id="id" :value="target" :name="name" @change="change" v-model="val")
label(:for="id" :class="$style.content")
div
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' width="100%" viewBox='0 32 448 448' space='preserve')
use(xlink:href='#icon-check')
span
slot
</template>
<script>
export default {
props: {
target: {},
value: {},
id: {
type: String,
required: true,
},
name: {
type: String,
},
need: {
type: Boolean,
default: false,
},
},
data() {
return {
val: false,
}
},
watch: {
value(n) {
if (this.target && n !== this.target) {
this.val = this.need
? n === this.target
? this.target
: false
: n === this.target
} else if (n !== this.val) {
this.val = n
}
},
},
mounted() {
if (this.target) {
this.val = this.need
? this.value === this.target
? this.target
: false
: this.value === this.target
} else {
this.val = this.value
}
},
methods: {
change() {
let val = this.target == null ? this.val : this.val ? this.target : null
this.$emit('input', val)
this.$emit('change', val)
},
},
}
</script>
<style lang="less" module>
@import '../../assets/styles/layout.less';
.checkbox {
display: inline-block;
// font-size: 56px;
> input {
display: none;
&:checked {
+ .content {
> div {
&:after {
border-color: @color-theme;
}
svg {
transform: scale(1);
opacity: 1;
}
}
}
}
}
}
.content {
display: flex;
justify-content: center;
> div {
flex: none;
position: relative;
display: inline-block;
width: 1em;
height: 1em;
cursor: pointer;
display: flex;
color: @color-theme;
// border: 1px solid #ccc;
&:after {
position: absolute;
content: ' ';
top: 0;
bottom: 0;
left: 0;
right: 0;
border: 1px solid #ccc;
transition: border-color 0.2s ease;
border-radius: 15%;
}
svg {
transition: 0.2s ease;
transition-property: transform, opacity;
transform: scale(0.5);
opacity: 0;
}
}
> span {
flex: auto;
line-height: 1;
margin-left: 5px;
cursor: pointer;
}
}
each(@themes, {
:global(#container.@{value}) {
.checkbox {
> input {
&:checked {
+ .content {
> div {
&:after {
border-color: ~'@{color-@{value}-theme}';
}
}
}
}
}
}
.content {
> div {
color: ~'@{color-@{value}-theme}';
// border: 1px solid #ccc;
&:after {
border-color: #ccc;
}
}
}
}
})
</style>
@@ -0,0 +1,94 @@
<template lang="pug">
material-modal(:show="show" :bg-close="bgClose" @close="handleClose")
main(:class="$style.main")
h2
| {{ info.name }}
br
| {{ info.singer }}
material-btn(:class="$style.btn" :key="type.type" @click="handleClick(type.type)" v-for="type in info.types") {{getTypeName(type.type)}} {{ type.type.toUpperCase() }}{{ type.size && ` - ${type.size.toUpperCase()}` }}
</template>
<script>
export default {
props: {
show: {
type: Boolean,
default: false,
},
musicInfo: {
type: Object,
},
bgClose: {
type: Boolean,
default: true,
},
},
computed: {
info() {
return this.musicInfo || {}
},
},
methods: {
handleClick(type) {
this.$emit('select', type)
},
handleClose() {
this.$emit('close')
},
getTypeName(type) {
switch (type) {
case 'flac':
case 'ape':
return '无损音质'
case '320k':
return '高品音质'
case '192k':
case '128k':
return '普通音质'
}
},
},
}
</script>
<style lang="less" module>
@import '../../assets/styles/layout.less';
.main {
padding: 15px;
max-width: 300px;
min-width: 200px;
display: flex;
flex-flow: column nowrap;
justify-content: center;
h2 {
font-size: 13px;
color: @color-theme_2-font;
line-height: 1.3;
text-align: center;
margin-bottom: 15px;
}
}
.btn {
display: block;
margin-bottom: 15px;
&:last-child {
margin-bottom: 0;
}
}
each(@themes, {
:global(#container.@{value}) {
.main {
h2 {
color: ~'@{color-@{value}-theme_2-font}';
}
}
}
})
</style>
@@ -0,0 +1,106 @@
<template lang="pug">
div(:class="$style.btns")
button(type="button" v-if="playBtn" title="播放" @click.stop="handleClick('play')")
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 287.386 287.386' space='preserve')
use(xlink:href='#icon-testPlay')
button(type="button" v-if="downloadBtn" title="下载" @click.stop="handleClick('download')")
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 475.078 475.077' space='preserve')
use(xlink:href='#icon-download')
button(type="button" title="添加" v-if="userInfo" @click.stop="handleClick('add')")
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 42 42' space='preserve')
use(xlink:href='#icon-addTo')
button(type="button" v-if="removeBtn" title="移除" @click.stop="handleClick('remove')")
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 212.982 212.982' space='preserve')
use(xlink:href='#icon-delete')
button(type="button" v-if="searchBtn" title="搜索" @click.stop="handleClick('search')")
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 30.239 30.239' space='preserve')
use(xlink:href='#icon-search')
</template>
<script>
import { mapGetters } from 'vuex'
export default {
props: {
index: {
type: Number,
required: true,
},
removeBtn: {
type: Boolean,
default: true,
},
downloadBtn: {
type: Boolean,
default: true,
},
playBtn: {
type: Boolean,
default: true,
},
searchBtn: {
type: Boolean,
default: false,
},
},
computed: {
...mapGetters(['userInfo']),
},
methods: {
handleClick(action) {
this.$emit('btn-click', { action, index: this.index })
},
},
}
</script>
<style lang="less" module>
@import '../../assets/styles/layout.less';
.btns {
button {
background-color: transparent;
border: none;
border-radius: 3px;
margin-right: 5px;
cursor: pointer;
padding: 4px 7px;
color: @color-btn;
outline: none;
transition: background-color 0.2s ease;
line-height: 0;
&:last-child {
margin-right: 0;
}
svg {
height: 1.2em;
}
&:hover {
background-color: @color-theme_2-hover;
}
&:active {
background-color: @color-theme_2-active;
}
}
}
each(@themes, {
:global(#container.@{value}) {
.btns {
button {
color: ~'@{color-@{value}-btn}';
&:hover {
background-color: ~'@{color-@{value}-theme_2-hover}';
}
&:active {
background-color: ~'@{color-@{value}-theme_2-active}';
}
}
}
}
})
</style>
+199
View File
@@ -0,0 +1,199 @@
<template lang="pug">
transition(enter-active-class="animated fadeIn"
leave-active-class="animated fadeOut")
div(:class="$style.modal" v-show="show" @click="bgClose && close()")
transition(:enter-active-class="inClass"
:leave-active-class="outClass")
div(:class="$style.content" v-show="show" @click.stop)
header(:class="$style.header")
button(type="button" @click="close")
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 212.982 212.982' space='preserve')
use(xlink:href='#icon-delete')
slot
</template>
<script>
import { getRandom } from '../../utils'
import { mapGetters } from 'vuex'
export default {
props: {
show: {
type: Boolean,
default: false,
},
bgClose: {
type: Boolean,
default: false,
},
},
data() {
return {
animateIn: [
'flipInX',
'flipInY',
'fadeIn',
'bounceIn',
'lightSpeedIn',
'rotateInDownLeft',
'rotateInDownRight',
'rotateInUpLeft',
'rotateInUpRight',
'rollIn',
'zoomIn',
'zoomInDown',
'zoomInLeft',
'zoomInRight',
'zoomInUp',
'slideInDown',
'slideInLeft',
'slideInRight',
'slideInUp',
],
animateOut: [
'flipOutX',
'flipOutY',
'fadeOut',
'bounceOut',
'lightSpeedOut',
'rotateOutDownLeft',
'rotateOutDownRight',
'rotateOutUpLeft',
'rotateOutUpRight',
'rollOut',
'zoomOut',
'zoomOutDown',
'zoomOutLeft',
'zoomOutRight',
'zoomOutUp',
'slideOutDown',
'slideOutLeft',
'slideOutRight',
'slideOutUp',
'hinge',
],
inClass: 'animated flipInX',
outClass: 'animated flipOutX',
unwatchFn: null,
}
},
computed: {
...mapGetters(['setting']),
},
watch: {
'setting.randomAnimate': {
handler(n) {
if (n) {
this.unwatchFn = this.$watch('show', function(n) {
if (n) {
this.inClass = 'animated ' + this.animateIn[getRandom(0, this.animateIn.length)]
this.outClass = 'animated ' + this.animateOut[getRandom(0, this.animateOut.length)]
}
})
} else {
this.unwatchFn && this.unwatchFn()
}
},
immediate: true,
},
},
mounted() {
},
methods: {
close() {
this.$emit('close')
},
},
}
</script>
<style lang="less" module>
@import '../../assets/styles/layout.less';
.modal {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, .3);
display: grid;
align-items: center;
justify-items: center;
z-index: 99;
}
.content {
border-radius: 5px;
box-shadow: 0 0 3px rgba(0, 0, 0, .3);
overflow: hidden;
max-height: 70%;
max-width: 70%;
position: relative;
display: flex;
flex-flow: column nowrap;
> * {
background-color: @color-theme_2;
}
}
.header {
flex: none;
background-color: @color-theme;
display: flex;
justify-content: flex-end;
button {
border: none;
cursor: pointer;
padding: 4px 7px;
background-color: transparent;
color: @color-theme-font-label;
outline: none;
transition: background-color 0.2s ease;
line-height: 0;
svg {
height: .7em;
}
&:hover {
background-color: @color-theme-hover;
}
&:active {
background-color: @color-theme_2-active;
}
}
}
each(@themes, {
:global(#container.@{value}) {
.modal {
background-color: rgba(0, 0, 0, .3);
}
.content {
box-shadow: 0 0 3px rgba(0, 0, 0, .3);
> * {
background-color: ~'@{color-@{value}-theme_2}';
}
}
.header {
background-color: ~'@{color-@{value}-theme}';
button {
color: ~'@{color-@{value}-theme-font-label}';
&:hover {
background-color: ~'@{color-@{value}-theme-hover}';
}
&:active {
background-color: ~'@{color-@{value}-theme_2-active}';
}
}
}
}
})
</style>
@@ -0,0 +1,227 @@
<template lang="pug">
div(:class="$style.pagination" v-if="allPage > 1")
ul
li(v-if="page===1" :class="$style.disabled")
span
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 451.846 451.847' space='preserve')
use(xlink:href='#icon-left')
li(v-else)
button(type="button" @click="handleClick(page - 1)" title="上一页")
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 451.846 451.847' space='preserve')
use(xlink:href='#icon-left')
li(v-if="allPage > btnLength && page > pageEvg+1" :class="$style.first")
button(type="button" @click="handleClick(1)" title="第 1 页")
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 451.846 451.847' space='preserve')
use(xlink:href='#icon-first')
li(v-for="(p, index) in pages" :key="index" :class="{[$style.active] : p == page}")
span(v-if="p === page" v-text="page")
button(v-else type="button" @click="handleClick(p)" v-text="p" :title="`第 ${p} 页`")
li(v-if="allPage > btnLength && allPage - page > pageEvg" :class="$style.last")
button(type="button" @click="handleClick(allPage)" :title="`第 ${allPage} 页`")
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 451.846 451.847' space='preserve')
use(xlink:href='#icon-last')
li(v-if="page===allPage" :class="$style.disabled")
span
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 451.846 451.847' space='preserve')
use(xlink:href='#icon-right')
li(v-else)
button(type="button" @click="handleClick(page + 1)" title="下一页")
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 451.846 451.847' space='preserve')
use(xlink:href='#icon-right')
</template>
<script>
import { mapGetters } from 'vuex'
export default {
props: {
count: {
type: Number,
default: 0,
},
limit: {
type: Number,
default: 10,
},
page: {
type: Number,
default: 1,
},
btnLength: {
type: Number,
default: 7,
},
},
data() {
return {
pageArr: [],
}
},
computed: {
...mapGetters(['userInfo']),
allPage() {
return Math.ceil(this.count / this.limit) || 1
},
pageEvg() {
return Math.floor(this.btnLength / 2)
},
pages() {
if (this.allPage <= this.btnLength) return this.pageArr
let start =
this.page - this.pageEvg > 1
? this.allPage - this.page < this.pageEvg + 1
? this.allPage - (this.btnLength - 1)
: this.page - this.pageEvg
: 1
let end =
this.page + this.pageEvg <= this.btnLength
? this.btnLength
: this.page + this.pageEvg <= this.allPage
? this.page + this.pageEvg
: this.allPage
// console.log(start-1);
// console.log(end);
// console.log(this.pageArr.slice(start-1, end-1));
return this.pageArr.slice(start - 1, end)
},
},
watch: {
allPage() {
this.initPageArr()
},
},
methods: {
initPageArr() {
this.pageArr = []
for (let i = 1; i <= this.allPage; i++) this.pageArr.push(i)
},
handleClick(page) {
this.$emit('btn-click', page)
},
},
mounted() {
this.initPageArr()
},
}
</script>
<style lang="less" module>
@import '../../assets/styles/layout.less';
.pagination {
display: inline-block;
background-color: @color-pagination-background;
// border-top-left-radius: 8px;
border-radius: 4px;
ul {
display: flex;
flex-flow: row nowrap;
// border: .0625rem solid @theme_color2;
// border-radius: .3125rem;
li {
// margin-right: @padding;
color: @color-theme;
// border: .0625rem solid @theme_line;
// border-radius: .3125rem;
transition: 0.4s ease;
transition-property: all;
line-height: 1;
display: flex;
// border-right: none;
svg {
height: 1em;
}
span,
button {
display: block;
padding: 7px 12px;
line-height: 1;
color: @color-theme;
font-size: 13px;
}
&.active {
span {
background-color: @color-pagination-select;
}
}
button {
background-color: transparent;
border: none;
cursor: pointer;
outline: none;
transition: background-color .3s ease;
&:hover {
background-color: @color-pagination-hover;
}
&:active {
background-color: @color-pagination-active;
}
}
&.disabled {
span {
opacity: .3;
}
}
&:first-child {
span, button {
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
// border-right: .0625rem solid @theme_line;
}
&:last-child {
span, button {
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
// border-right: .0625rem solid @theme_line;
}
&:first-child, &:last-child, &.first, &.last {
span,
button {
line-height: 0;
}
}
}
}
}
each(@themes, {
:global(#container.@{value}) {
.pagination {
background-color: ~'@{color-@{value}-pagination-background}';
ul {
li {
color: ~'@{color-@{value}-theme}';
span,
button {
color: ~'@{color-@{value}-theme}';
}
&.active {
span {
background-color: ~'@{color-@{value}-pagination-select}';
}
}
button {
&:hover {
background-color: ~'@{color-@{value}-pagination-hover}';
}
&:active {
background-color: ~'@{color-@{value}-pagination-active}';
}
}
}
}
}
}
})
</style>
@@ -0,0 +1,232 @@
<template lang="pug">
div(:class="[$style.search, focus ? $style.active : '']")
div(:class="$style.form")
input(placeholder="Search for something..." v-model.trim="text"
@focus="handleFocus" @blur="handleBlur" @input="handleInput"
@keyup.enter="handleSearch")
button(type="button" @click="handleSearch")
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 30.239 30.239' space='preserve')
use(xlink:href='#icon-search')
//- transition(name="custom-classes-transition"
//- enter-active-class="animated flipInX"
//- leave-active-class="animated flipOutX")
div(:class="$style.list" :style="listStyle")
ul(ref="dom_list")
li(v-for="(item, index) in list" :key="item" @click="handleTemplistClick(index)")
span {{item}}
</template>
<script>
import { mapGetters } from 'vuex'
import music from '../../utils/music'
export default {
data() {
return {
isShow: false,
text: '',
list: [],
index: null,
focus: false,
listStyle: {
height: 0,
},
}
},
computed: {
...mapGetters(['source']),
...mapGetters('search', ['info']),
},
watch: {
list(n) {
this.$nextTick(() => {
this.listStyle.height = this.$refs.dom_list.scrollHeight + 'px'
})
},
'info.text'(n) {
if (n !== this.text) this.text = n
},
},
methods: {
handleTemplistClick(index) {
this.text = this.list[index]
this.handleSearch()
},
handleFocus() {
this.focus = true
if (this.text) this.handleInput()
this.showList()
},
handleBlur() {
setTimeout(() => {
this.focus = false
this.hideList()
}, 200)
},
handleSearch() {
this.hideList()
this.$router.push({
path: 'search',
query: {
text: this.text,
},
})
},
handleInput() {
if (this.text === '') {
this.list.splice(0, this.list.length)
music[this.source.id].tempSearch.cancelTempSearch()
return
}
if (!this.isShow) this.showList()
music[this.source.id].tempSearch.search(this.text).then(list => {
this.list = list
}).catch(() => {})
},
showList() {
this.isShow = true
this.listStyle.height = this.$refs.dom_list.scrollHeight + 'px'
},
hideList() {
this.isShow = false
this.listStyle.height = 0
},
},
}
</script>
<style lang="less" module>
@import '../../assets/styles/layout.less';
.search {
position: absolute;
left: 15px;
top: 13px;
border-radius: 3px;
transition: box-shadow .4s ease, background-color @transition-theme;
display: flex;
flex-flow: column nowrap;
width: 240px;
background-color: @color-search-form-background;
&.active {
box-shadow: 0 1px 5px 0 rgba(0,0,0,.2);
.form {
input {
border-bottom-left-radius: 0;
}
button {
border-bottom-right-radius: 0;
}
}
}
.form {
display: flex;
height: @height-toolbar / 2;
position: relative;
input {
flex: auto;
// border: 1px solid;
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
background-color: transparent;
// border-bottom: 2px solid @color-theme;
// border-color: @color-theme;
border: none;
outline: none;
// height: @height-toolbar * .7;
padding: 0 5px;
overflow: hidden;
&::placeholder {
color: @color-btn;
}
}
button {
flex: none;
border: none;
// background-color: @color-search-form-background;
background-color: transparent;
outline: none;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
cursor: pointer;
height: 100%;
padding: 5px 7px;
color: @color-btn;
transition: background-color .2s ease;
&:hover {
background-color: @color-theme-hover;
}
&:active {
background-color: @color-theme-active;
}
}
}
.list {
// background-color: @color-search-form-background;
font-size: 13px;
transition: .3s ease;
height: 0;
transition-property: height;
overflow: hidden;
li {
cursor: pointer;
padding: 8px 5px;
transition: background-color .2s ease;
line-height: 1.3;
span {
.mixin-ellipsis-2;
}
&:hover {
background-color: @color-search-list-hover;
}
&:last-child {
border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
}
}
}
}
each(@themes, {
:global(#container.@{value}) {
.search {
background-color: ~'@{color-@{value}-search-form-background}';
&.active {
box-shadow: 0 1px 5px 0 rgba(0,0,0,.2);
}
.form {
input {
&::placeholder {
color: ~'@{color-@{value}-btn}';
}
}
button {
color: ~'@{color-@{value}-btn}';
&:hover {
background-color: ~'@{color-@{value}-theme-hover}';
}
&:active {
background-color: ~'@{color-@{value}-theme-active}';
}
}
}
.list {
li {
&:hover {
background-color: ~'@{color-@{value}-search-list-hover}';
}
}
}
}
}
})
</style>
+170
View File
@@ -0,0 +1,170 @@
<template lang="pug">
div(:class="$style.select")
div(:class="$style.label" ref="dom_btn" @click="handleShow") {{value ? itemName ? list.find(l => l.id == value).name : value : ''}}
ul(:class="$style.list" ref="dom_list" :style="listStyle")
li(v-for="item in list" @click="handleClick(itemKey ? item[itemKey] : item)") {{itemName ? item[itemName] : item}}
</template>
<script>
// import { isChildren } from '../../utils'
export default {
props: {
list: {
type: Array,
default() {
return []
},
},
value: {
type: [String, Number],
},
itemName: {
type: String,
},
itemKey: {
type: String,
},
},
data() {
return {
show: false,
listStyle: {
height: 0,
opacity: 0,
},
}
},
watch: {
show(n) {
this.$nextTick(() => {
if (n) {
this.listStyle.height = this.$refs.dom_list.scrollHeight + 'px'
this.listStyle.opacity = 1
} else {
this.listStyle.height = 0
this.listStyle.opacity = 0
}
})
},
},
mounted() {
document.addEventListener('click', this.handleHide)
},
beforeDestroy() {
document.removeEventListener('click', this.handleHide)
},
methods: {
handleHide(e) {
// if (e && e.target.parentNode != this.$refs.dom_list && this.show) return this.show = false
if (e && e.target == this.$refs.dom_btn) return
setTimeout(() => {
this.show = false
}, 50)
},
handleClick(item) {
if (item === this.value) return
this.$emit('input', item)
this.$emit('change', item)
},
handleShow() {
this.show = !this.show
},
},
}
</script>
<style lang="less" module>
@import '../../assets/styles/layout.less';
.select {
font-size: 12px;
position: relative;
}
.label {
padding: 8px 15px;
// background-color: @color-btn-background;
transition: background-color @transition-theme;
border-top: 2px solid @color-tab-border-bottom;
border-left: 2px solid @color-tab-border-bottom;
box-sizing: border-box;
text-align: center;
border-top-left-radius: 3px;
color: @color-btn;
cursor: pointer;
&:hover {
background-color: @color-theme_2-hover;
}
&:active {
background-color: @color-theme_2-active;
}
}
.list {
position: absolute;
top: 100%;
left: 0;
border-bottom: 2px solid @color-tab-border-bottom;
border-left: 2px solid @color-tab-border-bottom;
border-bottom-left-radius: 3px;
background-color: @color-theme_2;
overflow: hidden;
opacity: 0;
transition: .25s ease;
transition-property: height, opacity;
z-index: 10;
li {
cursor: pointer;
padding: 8px 15px;
// color: @color-btn;
text-align: center;
outline: none;
transition: background-color @transition-theme;
background-color: @color-btn-background;
box-sizing: border-box;
&:hover {
background-color: @color-theme_2-hover;
}
&:active {
background-color: @color-theme_2-active;
}
}
}
each(@themes, {
:global(#container.@{value}) {
.label {
border-top-color: ~'@{color-@{value}-tab-border-bottom}';
border-left-color: ~'@{color-@{value}-tab-border-bottom}';
color: ~'@{color-@{value}-btn}';
&:hover {
background-color: ~'@{color-@{value}-theme_2-hover}';
}
&:active {
background-color: ~'@{color-@{value}-theme_2-active}';
}
}
.list {
border-bottom-color: ~'@{color-@{value}-tab-border-bottom}';
border-left-color: ~'@{color-@{value}-tab-border-bottom}';
li {
// color: ~'@{color-@{value}-btn}';
background-color: ~'@{color-@{value}-btn-background}';
&:hover {
background-color: ~'@{color-@{value}-theme_2-hover}';
}
&:active {
background-color: ~'@{color-@{value}-theme_2-active}';
}
}
}
}
})
</style>
+221
View File
@@ -0,0 +1,221 @@
<template lang="pug">
div.scroll(:class="$style.tab")
//- div(:class="$style.content")
ul
li(v-for="item in list" :key="itemKey ? item[itemKey] : item" :class="value === (itemKey ? item[itemKey] : item) ? $style.active : ''")
button(type="button"
@click="handleClick(itemKey ? item[itemKey] : item)") {{ itemName ? item[itemName] : item }}
//- div(:class="$style.control")
div(:class="$style.left")
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 451.846 451.847' space='preserve')
use(xlink:href='#icon-left')
div(:class="$style.right")
svg(version='1.1' xmlns='http://www.w3.org/2000/svg' xlink='http://www.w3.org/1999/xlink' height='100%' viewBox='0 0 451.846 451.847' space='preserve')
use(xlink:href='#icon-right')
</template>
<script>
export default {
props: {
list: {
type: Array,
default() {
return []
},
},
value: {
type: [String, Number],
},
itemName: {
type: String,
},
itemKey: {
type: String,
},
},
methods: {
handleClick(item) {
if (item === this.value) return
this.$emit('input', item)
this.$emit('change', item)
},
},
}
</script>
<style lang="less" module>
@import '../../assets/styles/layout.less';
.tab {
// overflow: hidden;
// display: flex;
// flex-flow: row nowrap;
overflow-x: auto;
ul {
display: flex;
flex: none;
border-bottom: 2px solid @color-tab-border-bottom;
transition: border-bottom-color @transition-theme;
li {
position: relative;
flex: none;
margin-bottom: -2px;
border-top: 2px solid @color-tab-border-top;
border-left: 2px solid @color-tab-btn-background;
border-right: 2px solid @color-tab-btn-background;
// box-sizing: border-box;
transition: border-color @transition-theme;
margin-left: -2px;
&::after {
content: ' ';
display: block;
width: 50%;
height: 2px;
position: absolute;
bottom: 0;
left: 0;
background-color: @color-tab-border-bottom;
transition: width @transition-theme;
}
&::before {
content: ' ';
display: block;
width: 50%;
height: 2px;
position: absolute;
bottom: 0;
right: 0;
background-color: @color-tab-border-bottom;
transition: width @transition-theme;
}
&:first-child {
border-left: none;
margin-left: 0;
button {
border-top-left-radius: 3px;
// border-bottom-left-radius: 3px;
}
}
&:last-child {
border-right: 2px solid @color-tab-border-top;
border-top-right-radius: 3px;
button {
border-top-right-radius: 3px;
// border-bottom-right-radius: 3px;
}
}
button {
display: inline-block;
border: none;
cursor: pointer;
padding: 5px 10px 7px;
font-size: 12px;
// color: @color-btn;
outline: none;
transition: background-color @transition-theme;
background-color: @color-tab-btn-background;
}
&:hover {
// border-left-color: @color-theme_2-hover;
// border-right-color: @color-theme_2-hover;
button {
background-color: @color-theme_2-hover;
}
}
&:active {
// border-left-color: @color-theme_2-active;
// border-right-color: @color-theme_2-active;
button {
background-color: @color-theme_2-active;
}
}
&.active {
border-bottom-color: @color-theme_2;
border-top-color: @color-tab-border-bottom;
border-left-color: @color-tab-border-bottom;
border-right-color: @color-tab-border-bottom;
&::after {
width: 0;
}
&::before {
width: 0;
}
button {
background-color: @color-theme_2;
}
}
}
}
}
// .control {
// flex: none;
// border-bottom: 2px solid @color-tab-border-bottom;
// width: 1em;
// svg {
// width: .85em;
// }
// }
// .left, .right {
// line-height: 0;
// }
// .content {
// flex: auto;
// overflow: hidden;
// }
each(@themes, {
:global(#container.@{value}) {
.tab {
ul {
border-bottom-color: ~'@{color-@{value}-tab-border-bottom}';
li {
border-top-color: ~'@{color-@{value}-tab-border-top}';
border-left-color: ~'@{color-@{value}-tab-btn-background}';
border-right-color: ~'@{color-@{value}-tab-btn-background}';
&::after {
background-color: ~'@{color-@{value}-tab-border-bottom}';
}
&::before {
background-color: ~'@{color-@{value}-tab-border-bottom}';
}
&:last-child {
border-right-color: ~'@{color-@{value}-tab-border-top}';
}
button {
// color: ~'@{color-@{value}-btn}';
background-color: ~'@{color-@{value}-tab-btn-background}';
}
&:hover {
// border-left-color: ~'@{color-@{value}-theme_2-hover}';
// border-right-color: ~'@{color-@{value}-theme_2-hover}';
button {
background-color: ~'@{color-@{value}-theme_2-hover}';
}
}
&:active {
// border-left-color: ~'@{color-@{value}-theme_2-active}';
// border-right-color: ~'@{color-@{value}-theme_2-active}';
button {
background-color: ~'@{color-@{value}-theme_2-active}';
}
}
&.active {
border-bottom-color: ~'@{color-@{value}-theme_2}';
border-top-color: ~'@{color-@{value}-tab-border-bottom}';
border-left-color: ~'@{color-@{value}-tab-border-bottom}';
border-right-color: ~'@{color-@{value}-tab-border-bottom}';
button {
background-color: ~'@{color-@{value}-theme_2}';
}
}
}
}
}
}
})
</style>
@@ -0,0 +1,156 @@
<template lang="pug">
material-modal(:show="version.showModal" @close="handleClose")
main(:class="$style.main" v-if="version.newVersion")
h2 🚀程序更新🚀
div.scroll(:class="$style.info")
div(:class="$style.current")
h3 最新版本:{{version.newVersion.version}}
h3 当前版本:{{version.version}}
h3 版本变化:
p(v-html="version.newVersion.desc")
div(:class="$style.history" v-if="history.length")
h3 历史版本:
div(:class="$style.item" v-for="ver in history")
h4 v{{ver.version}}
p(v-html="ver.desc")
div(:class="$style.footer")
div(:class="$style.desc")
p 新版本已下载完毕,
p
| 你可以选择
strong 立即重启更新
| 或稍后
strong 关闭程序时
| 自动更新~
material-btn(:class="$style.btn" @click.onec="handleClick") 立即重启更新
</template>
<script>
import { mapGetters, mapMutations } from 'vuex'
import { rendererSend } from '../../../common/icp'
import { checkVersion } from '../../utils'
export default {
computed: {
...mapGetters(['version']),
history() {
if (!this.version.newVersion) return []
let arr = []
let currentVer = this.version.version
this.version.newVersion.history.forEach(ver => {
if (checkVersion(currentVer, ver.version)) arr.push(ver)
})
return arr
},
},
methods: {
...mapMutations(['setVersionVisible']),
handleClose() {
this.setVersionVisible(false)
},
handleClick(event) {
this.handleClose()
event.target.disabled = true
rendererSend('quit-update')
},
},
}
</script>
<style lang="less" module>
@import '../../assets/styles/layout.less';
.main {
position: relative;
padding: 15px;
max-width: 500px;
min-width: 300px;
display: flex;
flex-flow: column nowrap;
justify-content: center;
// 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;
}
}
.info {
flex: 1 1 auto;
font-size: 13px;
line-height: 1.5;
overflow-y: auto;
height: 100%;
}
.current {
> p {
padding-left: 15px;
}
}
.history {
h3 {
padding-top: 15px;
}
.item {
+ .item {
padding-top: 15px;
}
h4 {
font-weight: 700;
}
> p {
padding-left: 10px;
}
}
}
.footer {
flex: 0 0 none;
.desc {
font-size: 12px;
padding: 10px 0;
color: @color-theme;
line-height: 1.2;
strong {
text-decoration: underline;
}
}
}
.btn {
display: block;
width: 100%;
}
each(@themes, {
:global(#container.@{value}) {
.main {
h2 {
color: ~'@{color-@{value}-theme_2-font}';
}
}
.footer {
.desc {
color: ~'@{color-@{value}-theme}';
}
}
}
})
</style>