初步设计了按钮和播放列表的ui
parent
a22a9ffc85
commit
44fe92df94
|
@ -4,8 +4,12 @@
|
||||||
<div id="right">
|
<div id="right">
|
||||||
<layout-toolbar id="toolbar" />
|
<layout-toolbar id="toolbar" />
|
||||||
<div class="middle">
|
<div class="middle">
|
||||||
<layout-view id="view" />
|
<layout-view id="view" ref="viewRef" />
|
||||||
<PlayListWindow v-if="isShowPlaylist" class="playlist-window" @close="closePlaylist()" />
|
<PlayListWindow
|
||||||
|
v-if="isShowPlaylist"
|
||||||
|
:style="playlistStyle"
|
||||||
|
@close="closePlaylist"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<layout-play-bar id="player" />
|
<layout-play-bar id="player" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -21,20 +25,37 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted } from '@common/utils/vueTools'
|
import { nextTick, onMounted, ref, computed } from '@common/utils/vueTools'
|
||||||
import useApp from '@renderer/core/useApp'
|
import useApp from '@renderer/core/useApp'
|
||||||
import PlayListWindow from '@renderer/components/common/PlayListWindow.vue'
|
import PlayListWindow from '@renderer/components/common/PlayListWindow.vue'
|
||||||
import { isShowPlaylist } from '@renderer/store/player/state'
|
import { isShowPlaylist } from '@renderer/store/player/state'
|
||||||
import { setShowPlaylist } from '@renderer/store/player/action'
|
import { setShowPlaylist } from '@renderer/store/player/action'
|
||||||
|
|
||||||
|
const viewRef = ref(null)
|
||||||
|
|
||||||
|
const playlistStyle = computed(() => {
|
||||||
|
const el = viewRef.value?.$el || viewRef.value
|
||||||
|
if (!el) return {}
|
||||||
|
const rect = el.getBoundingClientRect()
|
||||||
|
return {
|
||||||
|
position: 'absolute',
|
||||||
|
left: `${rect.left}px`,
|
||||||
|
top: `${rect.top}px`,
|
||||||
|
height: `${rect.height}px`,
|
||||||
|
width: `${rect.width}px`,
|
||||||
|
zIndex: 1000,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const closePlaylist = () => {
|
const closePlaylist = () => {
|
||||||
setShowPlaylist(false)
|
setShowPlaylist(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
useApp()
|
useApp()
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(async () => {
|
||||||
document.getElementById('root').style.display = 'block'
|
document.getElementById('root').style.display = 'block'
|
||||||
|
await nextTick()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -42,15 +63,10 @@ onMounted(() => {
|
||||||
@import './assets/styles/index.less';
|
@import './assets/styles/index.less';
|
||||||
@import './assets/styles/layout.less';
|
@import './assets/styles/layout.less';
|
||||||
|
|
||||||
html {
|
|
||||||
height: 100vh;
|
|
||||||
}
|
|
||||||
html, body {
|
html, body {
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
body {
|
|
||||||
user-select: none;
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
user-select: none;
|
||||||
}
|
}
|
||||||
#root {
|
#root {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -61,44 +77,6 @@ body {
|
||||||
background-size: var(--background-image-size);
|
background-size: var(--background-image-size);
|
||||||
transition: background-color @transition-normal;
|
transition: background-color @transition-normal;
|
||||||
background-color: var(--color-content-background);
|
background-color: var(--color-content-background);
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.disableAnimation * {
|
|
||||||
transition: none !important;
|
|
||||||
animation: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.transparent {
|
|
||||||
background: transparent;
|
|
||||||
padding: @shadow-app;
|
|
||||||
#body {
|
|
||||||
border-radius: @radius-border;
|
|
||||||
}
|
|
||||||
#root {
|
|
||||||
box-shadow: 0 0 @shadow-app rgba(0, 0, 0, 0.5);
|
|
||||||
border-radius: @radius-border;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.disableTransparent {
|
|
||||||
background-color: var(--color-content-background);
|
|
||||||
|
|
||||||
#body {
|
|
||||||
border: 1Px solid var(--color-primary-light-500);
|
|
||||||
}
|
|
||||||
|
|
||||||
#right {
|
|
||||||
border-top-left-radius: 0;
|
|
||||||
border-bottom-left-radius: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.fullscreen {
|
|
||||||
background-color: var(--color-content-background);
|
|
||||||
|
|
||||||
#right {
|
|
||||||
border-top-left-radius: 0;
|
|
||||||
border-bottom-left-radius: 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#container {
|
#container {
|
||||||
|
@ -117,49 +95,35 @@ body {
|
||||||
flex: auto;
|
flex: auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
transition: background-color @transition-normal;
|
|
||||||
background-color: var(--color-main-background);
|
background-color: var(--color-main-background);
|
||||||
border-top-left-radius: @radius-border;
|
border-top-left-radius: @radius-border;
|
||||||
border-bottom-left-radius: @radius-border;
|
border-bottom-left-radius: @radius-border;
|
||||||
overflow: hidden;
|
|
||||||
box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#toolbar,
|
|
||||||
#player {
|
|
||||||
flex: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 中间区域横向布局 */
|
|
||||||
.middle {
|
.middle {
|
||||||
flex: auto;
|
flex: auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
overflow: hidden;
|
position: relative;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 主内容区域自动伸缩 */
|
|
||||||
#view {
|
#view {
|
||||||
position: relative;
|
position: relative;
|
||||||
flex: auto;
|
flex: auto;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 播放列表窗口,默认宽度固定 */
|
|
||||||
.playlist-window {
|
.playlist-window {
|
||||||
width: 300px;
|
position: relative;
|
||||||
flex: none;
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
border-left: 1px solid var(--color-border);
|
border-left: 1px solid var(--color-border);
|
||||||
background-color: var(--color-main-background);
|
background-color: var(--color-main-background);
|
||||||
}
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
|
||||||
|
border-radius: @radius-border;
|
||||||
.view-container {
|
overflow: hidden;
|
||||||
transition: opacity @transition-normal;
|
z-index: 1000;
|
||||||
}
|
|
||||||
#root.show-modal > .view-container {
|
|
||||||
opacity: .9;
|
|
||||||
}
|
|
||||||
#view.show-modal > .view-container {
|
|
||||||
opacity: .2;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -4,9 +4,10 @@
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { isShowPlaylist } from '@renderer/store/player/state'
|
||||||
import { setShowPlaylist } from '@renderer/store/player/action'
|
import { setShowPlaylist } from '@renderer/store/player/action'
|
||||||
const togglePlaylist = () => {
|
const togglePlaylist = () => {
|
||||||
setShowPlaylist(true)
|
setShowPlaylist(!isShowPlaylist.value)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
|
@ -1,31 +1,36 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="playlist-overlay">
|
|
||||||
<div class="playlist-window">
|
<div class="playlist-window">
|
||||||
<button class="close-button" @click="emitClose">✖</button>
|
<button class="close-button" @click="emitClose">✖</button>
|
||||||
<h2>播放列表</h2>
|
<h2 class="title">播放列表</h2>
|
||||||
<ul>
|
<div class="song-list">
|
||||||
<li v-for="(song, index) in songs" :key="index">
|
<div v-for="(song, index) in songs" :key="index" class="song-item">
|
||||||
{{ index + 1 }}. {{ song }}
|
<div class="song-index">{{ index + 1 }}</div>
|
||||||
</li>
|
<div class="song-info">
|
||||||
</ul>
|
<div class="song-title">{{ song.title }}</div>
|
||||||
|
<div class="song-meta">{{ song.artist }} · {{ song.album }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
|
|
||||||
const emit = defineEmits(['close'])
|
const emit = defineEmits(['close'])
|
||||||
|
|
||||||
const songs = ref([
|
const songs = ref([
|
||||||
'海阔天空 - Beyond',
|
{ title: '海阔天空', artist: 'Beyond', album: '乐与怒' },
|
||||||
'夜曲 - 周杰伦',
|
{ title: '夜曲', artist: '周杰伦', album: '十一月的萧邦' },
|
||||||
'告白气球 - 周杰伦',
|
{ title: '告白气球', artist: '周杰伦', album: '周杰伦的床边故事' },
|
||||||
'平凡之路 - 朴树',
|
{ title: '平凡之路', artist: '朴树', album: '平凡之路' },
|
||||||
])
|
])
|
||||||
|
|
||||||
const emitClose = () => {
|
const emitClose = () => {
|
||||||
emit('close')
|
emit('close')
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.playlist-overlay {
|
.playlist-overlay {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
@ -39,16 +44,27 @@ const emitClose = () => {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
z-index: 999;
|
z-index: 999;
|
||||||
}
|
}
|
||||||
|
|
||||||
.playlist-window {
|
.playlist-window {
|
||||||
background-color: #222;
|
background-color: #222;
|
||||||
color: white;
|
color: white;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
width: 300px;
|
width: 320px;
|
||||||
max-height: 80%;
|
max-height: 80%;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
.close-button {
|
.close-button {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 10px;
|
top: 10px;
|
||||||
|
@ -59,4 +75,49 @@ const emitClose = () => {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.song-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.song-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 6px;
|
||||||
|
background-color: #2c2c2c;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.song-item:hover {
|
||||||
|
background-color: #3a3a3a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.song-index {
|
||||||
|
width: 24px;
|
||||||
|
text-align: right;
|
||||||
|
margin-right: 10px;
|
||||||
|
color: #aaa;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.song-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.song-title {
|
||||||
|
font-size: 16px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.song-meta {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in New Issue