refactor: enhance UI compatibility

This commit is contained in:
qier222 2021-01-02 20:55:43 +08:00
parent 3c3e5e7569
commit acf3d768f8
14 changed files with 264 additions and 330 deletions

View file

@ -1,35 +1,30 @@
<template>
<div style="position: relative">
<div
class="cover"
@mouseover="focus = true"
@mouseleave="focus = false"
:style="coverStyle"
:class="{
'hover-float': hoverEffect,
'hover-play-button': showPlayButton,
}"
@click="clickToPlay ? play() : goTo()"
>
<button
class="play-button"
v-if="showPlayButton"
:style="playButtonStyle"
@click.stop="playButtonClicked"
>
<svg-icon icon-class="play" />
</button>
<div
class="cover"
@mouseover="focus = true"
@mouseleave="focus = false"
:class="{ 'cover-hover': coverHover }"
@click="clickCoverToPlay ? play() : goTo()"
>
<div class="cover-container">
<div class="shade">
<button
v-show="focus"
class="play-button"
@click.stop="play()"
:style="playButtonStyles"
><svg-icon icon-class="play" />
</button>
</div>
<img :src="imageUrl" :style="imageStyles" />
<transition name="fade" v-if="coverHover || alwaysShowShadow">
<div
class="shadow"
v-show="focus || alwaysShowShadow"
:style="shadowStyles"
></div>
</transition>
</div>
<transition name="fade" v-if="hoverEffect">
<img class="shadow" v-show="focus" :src="url" :style="shadowStyle"
/></transition>
<img
class="shadow"
v-if="alwaysShowShadow"
:src="url"
:style="shadowStyle"
/>
</div>
</template>
@ -37,83 +32,54 @@
import { playAlbumByID, playPlaylistByID, playArtistByID } from "@/utils/play";
export default {
name: "Cover",
props: {
id: Number,
type: String,
url: String,
hoverEffect: Boolean,
showPlayButton: Boolean,
alwaysShowShadow: Boolean,
showBlackShadow: Boolean,
clickToPlay: Boolean,
size: {
type: Number,
default: 208,
},
shadowMargin: {
type: Number,
default: 12,
},
radius: {
type: Number,
default: 12,
},
playButtonSize: {
type: Number,
default: 48,
},
id: { type: Number, required: true },
type: { type: String, required: true },
imageUrl: { type: String, required: true },
fixedSize: { type: Number, default: 0 },
playButtonSize: { type: Number, default: 22 },
coverHover: { type: Boolean, default: true },
alwaysShowPlayButton: { type: Boolean, default: true },
alwaysShowShadow: { type: Boolean, default: false },
clickCoverToPlay: { type: Boolean, default: false },
shadowMargin: { type: Number, default: 12 },
radius: { type: Number, default: 12 },
},
data() {
return {
focus: false,
shadowStyle: {},
playButtonStyle: {},
};
},
created() {
this.shadowStyle = {
height: `${this.size}px`,
width: `${~~(this.size * 0.96)}px`,
top: `${this.shadowMargin}px`,
right: `${~~(this.size * 0.02)}px`,
borderRadius: `${this.radius}px`,
};
this.playButtonStyle = {
height: `${this.playButtonSize}px`,
width: `${this.playButtonSize}px`,
};
},
computed: {
coverStyle() {
return {
backgroundImage: `url('${this.url}')`,
boxShadow: this.showBlackShadow
? "0 12px 16px -8px rgba(0, 0, 0, 0.2)"
: "",
height: `${this.size}px`,
width: `${this.size}px`,
borderRadius: `${this.radius}px`,
cursor: this.clickToPlay ? "default" : "pointer",
};
imageStyles() {
let styles = {};
if (this.fixedSize !== 0) {
styles.width = this.fixedSize + "px";
}
if (this.type === "artist") styles.borderRadius = "50%";
return styles;
},
playButtonStyles() {
let styles = {};
styles.width = this.playButtonSize + "%";
styles.height = this.playButtonSize + "%";
return styles;
},
shadowStyles() {
let styles = {};
styles.backgroundImage = `url(${this.imageUrl})`;
if (this.type === "artist") styles.borderRadius = "50%";
return styles;
},
},
methods: {
play() {
if (this.type === "album") {
playAlbumByID(this.id);
} else if (this.type === "playlist") {
playPlaylistByID(this.id);
}
},
playButtonClicked() {
if (this.type === "album") {
playAlbumByID(this.id);
} else if (this.type === "playlist") {
playPlaylistByID(this.id);
} else if (this.type === "artist") {
playArtistByID(this.id);
}
const playActions = {
album: playAlbumByID,
playlist: playPlaylistByID,
artist: playArtistByID,
};
playActions[this.type](this.id);
},
goTo() {
this.$router.push({ name: this.type, params: { id: this.id } });
@ -125,72 +91,70 @@ export default {
<style lang="scss" scoped>
.cover {
position: relative;
padding: 0;
background-size: cover;
transition: transform 0.3s;
}
.cover-container {
position: relative;
}
img {
border-radius: 0.75em;
width: 100%;
user-select: none;
}
.cover-hover {
&:hover {
cursor: pointer;
transform: scale(1.02);
}
}
.shade {
position: absolute;
top: 0;
height: calc(100% - 3px);
width: 100%;
background: transparent;
display: flex;
justify-content: center;
align-items: center;
transition: transform 0.3s;
}
.hover-float {
&:hover {
transform: scale(1.02);
box-shadow: 0 12px 16px -8px rgba(0, 0, 0, 0.05);
}
}
.hover-play-button {
&:hover {
.play-button {
opacity: 1;
transform: unset;
.play-button {
display: flex;
justify-content: center;
align-items: center;
color: white;
backdrop-filter: blur(12px) brightness(96%);
background: transparent;
height: 22%;
width: 22%;
border-radius: 50%;
cursor: default;
transition: 0.2s;
.svg-icon {
height: 44%;
margin: {
left: 4px;
}
}
.play-button {
&:hover {
transform: scale(1.06);
}
&:active {
transform: scale(0.94);
}
&:hover {
transform: scale(1.06);
}
&:active {
transform: scale(0.94);
}
}
.shadow {
position: absolute;
top: 12px;
height: 100%;
width: 100%;
filter: blur(16px) opacity(0.6);
transform: scale(0.92, 0.96);
z-index: -1;
height: 208px;
transform: scale(0.98);
}
[data-theme="dark"] {
.shadow {
filter: blur(16px) brightness(68%);
transform: scale(0.96);
}
}
.play-button {
opacity: 0;
display: flex;
justify-content: center;
align-items: center;
// right: 72px;
// top: 72px;
border: none;
backdrop-filter: blur(12px) brightness(96%);
background: transparent;
color: white;
border-radius: 50%;
cursor: default;
transition: 0.2s;
.svg-icon {
height: 50%;
margin: {
left: 3px;
}
}
background-size: cover;
border-radius: 0.75em;
}
.fade-enter-active,

View file

@ -2,23 +2,15 @@
<div class="cover-row">
<div
class="item"
:class="{ artist: type === 'artist' }"
v-for="item in items"
:key="item.id"
:style="{ marginBottom: subText === 'none' ? '32px' : '24px' }"
:class="{ artist: type === 'artist' }"
>
<Cover
class="cover"
:imageUrl="item.img1v1Url || item.picUrl || item.coverImgUrl"
:type="type"
:id="item.id"
:type="type === 'chart' ? 'playlist' : type"
:url="getUrl(item) | resizeImage(imageSize)"
:hoverEffect="true"
:showBlackShadow="true"
:showPlayButton="showPlayButton"
:radius="type === 'artist' ? 100 : 12"
:size="type === 'artist' ? 192 : 208"
/>
<div class="text">
<div class="info" v-if="showPlayCount">
<span class="play-count"
@ -27,22 +19,14 @@
}}
</span>
</div>
<div class="name">
<span
class="explicit-symbol"
v-if="type === 'album' && item.mark === 1056768"
<div class="title">
<span class="explicit-symbol" v-if="isExplicit(item)"
><ExplicitSymbol
/></span>
<span
class="lock-icon"
v-if="type === 'playlist' && item.privacy === 10"
>
<span class="lock-icon" v-if="isPrivacy(item)">
<svg-icon icon-class="lock"
/></span>
<router-link
:to="`/${type === 'chart' ? 'playlist' : type}/${item.id}`"
>{{ item.name }}</router-link
>
<router-link :to="getTitleLink(item)">{{ item.name }}</router-link>
</div>
<div class="info" v-if="type !== 'artist' && subText !== 'none'">
<span v-html="getSubText(item)"></span>
@ -53,8 +37,8 @@
</template>
<script>
import ExplicitSymbol from "@/components/ExplicitSymbol.vue";
import Cover from "@/components/Cover.vue";
import ExplicitSymbol from "@/components/ExplicitSymbol.vue";
export default {
name: "CoverRow",
@ -63,31 +47,12 @@ export default {
ExplicitSymbol,
},
props: {
items: Array,
type: String,
subText: {
type: String,
default: "none",
},
imageSize: {
type: Number,
default: 512,
},
showPlayButton: {
type: Boolean,
default: false,
},
showPlayCount: {
type: Boolean,
default: false,
},
items: { type: Array, required: true },
type: { type: String, required: true },
subText: { type: String, default: "null" },
showPlayCount: { type: Boolean, default: false },
},
methods: {
getUrl(item) {
if (item.picUrl !== undefined) return item.picUrl;
if (item.coverImgUrl !== undefined) return item.coverImgUrl;
if (item.img1v1Url !== undefined) return item.img1v1Url;
},
getSubText(item) {
if (this.subText === "copywriter") return item.copywriter;
if (this.subText === "description") return item.description;
@ -114,34 +79,35 @@ export default {
}
if (this.subText === "appleMusic") return "by Apple Music";
},
isPrivacy(item) {
return this.type === "playlist" && item.privacy === 10;
},
isExplicit(item) {
return this.type === "album" && item.mark === 1056768;
},
getTitleLink(item) {
let type = this.type === "chart" ? "playlist" : this.type;
return `/${type}/${item.id}`;
},
},
};
</script>
<style lang="scss" scoped>
.cover-row {
display: flex;
flex-wrap: wrap;
margin: {
right: -12px;
left: -12px;
}
.index-playlist {
margin: 12px 12px 24px 12px;
}
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 44px 24px;
}
.item {
margin: 12px 12px 24px 12px;
color: var(--color-text);
.text {
width: 208px;
margin-top: 8px;
.name {
.title {
font-size: 16px;
font-weight: 600;
line-height: 20px;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
@ -155,7 +121,6 @@ export default {
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
// margin-top: 4px;
}
}
}
@ -168,11 +133,17 @@ export default {
.cover {
display: flex;
}
.name {
.title {
margin-top: 4px;
}
}
@media (max-width: 834px) {
.item .text .title {
font-size: 14px;
}
}
.explicit-symbol {
opacity: 0.28;
color: var(--color-text);

View file

@ -1,20 +1,19 @@
<template>
<div class="mv-row">
<div class="mv" v-for="mv in mvs" :key="getID(mv)">
<div class="cover-container">
<img
class="cover"
:src="getUrl(mv)"
@mouseover="hoverVideoID = getID(mv)"
@mouseleave="hoverVideoID = 0"
@click="goToMv(getID(mv))"
/>
<div
class="cover"
@mouseover="hoverVideoID = getID(mv)"
@mouseleave="hoverVideoID = 0"
@click="goToMv(getID(mv))"
>
<img :src="getUrl(mv)" />
<transition name="fade">
<img
<div
class="shadow"
v-show="hoverVideoID === getID(mv)"
:src="getUrl(mv)"
/>
:style="{ background: 'url(' + getUrl(mv) + ')' }"
></div>
</transition>
</div>
<div class="info">
@ -87,14 +86,12 @@ export default {
<style lang="scss" scoped>
.mv-row {
display: flex;
flex-wrap: wrap;
margin-left: -12px;
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 36px 24px;
}
.mv {
margin: 12px 12px 24px 12px;
width: 204px;
color: var(--color-text);
.title {
@ -116,31 +113,30 @@ export default {
}
}
.cover-container {
.cover {
position: relative;
.cover {
position: relative;
padding: 0;
background-size: cover;
transition: 0.3s;
width: 200px;
border-radius: 10px;
transition: transform 0.3s;
&:hover {
cursor: pointer;
&:hover {
transform: scale(1.02);
box-shadow: 0 12px 16px -8px rgba(0, 0, 0, 0.05);
}
transform: scale(1.02);
}
}
img {
border-radius: 0.75em;
width: 100%;
user-select: none;
}
.shadow {
position: absolute;
filter: blur(16px) opacity(0.6);
z-index: -1;
width: 200px;
top: 6px;
left: 0;
border-radius: 10px;
}
.shadow {
position: absolute;
top: 6px;
height: 100%;
width: 100%;
filter: blur(16px) opacity(0.4);
transform: scale(0.9, 0.9);
z-index: -1;
background-size: cover;
border-radius: 0.75em;
}
.fade-enter-active,

View file

@ -105,13 +105,17 @@ nav {
}
backdrop-filter: saturate(180%) blur(20px);
// background: var(--color-body-bg);
// background-color: rgba(255, 255, 255, 0.86);
background-color: var(--color-navbar-bg);
z-index: 100;
-webkit-app-region: drag;
}
@media (max-width: 1336px) {
nav {
padding: 0 5vw;
}
}
.navigation-buttons {
flex: 1;
display: flex;
@ -124,6 +128,12 @@ nav {
-webkit-app-region: no-drag;
}
}
@media (max-width: 970px) {
.navigation-buttons {
flex: unset;
}
}
.navigation-links {
flex: 1;
display: flex;

View file

@ -335,6 +335,12 @@ export default {
}
}
@media (max-width: 1336px) {
.controls {
padding: 0 5vw;
}
}
.playing {
flex: 1;
display: flex;

View file

@ -1,5 +1,5 @@
<template>
<div class="track-list" :style="listStyles">
<div class="track-list">
<ContextMenu ref="menu">
<div class="item-info">
<img :src="rightClickedTrack.al.picUrl | resizeImage(224)" />
@ -26,13 +26,15 @@
>
<div class="item" @click="addTrackToPlaylist">添加到歌单</div>
</ContextMenu>
<TrackListItem
v-for="track in tracks"
:track="track"
:key="track.id"
@dblclick.native="playThisList(track.id)"
@click.right.native="openMenu($event, track)"
/>
<div :style="listStyles">
<TrackListItem
v-for="track in tracks"
:track="track"
:key="track.id"
@dblclick.native="playThisList(track.id)"
@click.right.native="openMenu($event, track)"
/>
</div>
</div>
</template>
@ -61,10 +63,6 @@ export default {
tracks: Array,
type: String,
id: Number,
itemWidth: {
type: Number,
default: -1,
},
dbclickTrackFunc: {
type: String,
default: "default",
@ -85,6 +83,10 @@ export default {
return []; // 'removeTrackFromPlaylist'
},
},
columnNumber: {
type: Number,
default: 4,
},
},
data() {
return {
@ -98,8 +100,13 @@ export default {
};
},
created() {
if (this.type === "tracklist")
this.listStyles = { display: "flex", flexWrap: "wrap" };
if (this.type === "tracklist") {
this.listStyles = {
display: "grid",
gap: "4px",
gridTemplateColumns: `repeat(${this.columnNumber}, 1fr)`,
};
}
},
computed: {
...mapState(["liked"]),

View file

@ -152,10 +152,6 @@ export default {
this.$parent.likeASong(this.track.id);
},
},
created() {
if (this.$parent.itemWidth !== -1)
this.trackStyle = { width: this.$parent.itemWidth + "px" };
},
};
</script>
@ -323,7 +319,6 @@ button {
}
.track.tracklist {
width: 256px;
img {
height: 36px;
width: 36px;