From 52ecb8a69793876666b02a49666bfc21ffa83a10 Mon Sep 17 00:00:00 2001 From: CosineSky <11737516+cosinesky@user.noreply.gitee.com> Date: Sat, 21 Dec 2024 16:30:37 +0800 Subject: [PATCH] - Added Playlist create/modify. --- src/api/playlist.js | 25 +- src/components/Header.vue | 251 +++++++++--------- src/components/LeftSideBar.vue | 86 ++++--- src/components/MainView.vue | 6 +- src/components/MusicAlbumView.vue | 41 +-- src/views/HomePage.vue | 7 +- src/views/a.vue | 412 ------------------------------ 7 files changed, 229 insertions(+), 599 deletions(-) delete mode 100644 src/views/a.vue diff --git a/src/api/playlist.js b/src/api/playlist.js index d3e146c..bf7574d 100644 --- a/src/api/playlist.js +++ b/src/api/playlist.js @@ -18,13 +18,30 @@ export const getPlaylistsByUser = (userInfo) => { /* // TODO - modified - user_name: string - playlist_name: string + - playlist_name: string + user_id: number - + playlist_description: string + - playlist_description: string */ export const createPlaylist = (playlistCreateInfo) => { - return axios.post(`${PLAYLIST_MODULE}/create`, playlistCreateInfo, - { headers: { 'Content-Type': 'application/json' } }) + console.log(playlistCreateInfo) + return axios.post(`${PLAYLIST_MODULE}/create`, null, + { params: playlistCreateInfo }) + .then(res => { + return res; + }); +} + +/* + // TODO - modified + + id: number + + title: string + + description: string + + picPath: string + */ +export const modifyPlaylist = (playlistModifyInfo) => { + console.log(playlistModifyInfo) + return axios.post(`${PLAYLIST_MODULE}/modify`, playlistModifyInfo, + {headers: {'Content-Type': 'application/json'}}) .then(res => { return res; }); diff --git a/src/components/Header.vue b/src/components/Header.vue index 3ceb4d6..36e06dc 100644 --- a/src/components/Header.vue +++ b/src/components/Header.vue @@ -1,7 +1,7 @@ <script setup> import {useRouter} from "vue-router"; import {ref} from "vue"; -import {searchSongByKeyword, searchPlaylistByKeyword} from "../api/search"; +import {searchPlaylistByKeyword, searchSongByKeyword} from "../api/search"; const router = useRouter(); const emit = defineEmits(['headData','home']); @@ -54,7 +54,7 @@ function callSearch() { songResult.value = []; playlistResult.value = []; showSearch.value = true - + searchSongByKeyword({ keyword: searchInput.value }).then(res => { @@ -95,11 +95,12 @@ function callHome() { <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-search" - @click="callSearch"> + @click="callSearch"> <circle cx="11" cy="11" r="8"></circle> <line x1="21" y1="21" x2="16.65" y2="16.65"></line> </svg> - <input type="text" v-model="searchInput" :placeholder="searchPlaceHolders[Math.floor(Math.random() * 5)]" @keyup.enter="callSearch"/> + <input type="text" v-model="searchInput" :placeholder="searchPlaceHolders[Math.floor(Math.random() * 5)]" + @keyup.enter="callSearch"/> </div> <div style="display: flex; flex-direction: row"> @@ -170,9 +171,9 @@ function callHome() { margin-right: 10px; color: #fff; text-decoration: none; - cursor: pointer; - border-radius: 50%; - transition: width, color, background-color ease-in-out 0.2s; + cursor: pointer; + border-radius: 50%; + transition: width, color, background-color ease-in-out 0.2s; } .home-btn svg { @@ -182,22 +183,22 @@ function callHome() { } .home-btn:hover { - transform: translateY(-2px); + transform: translateY(-2px); } .home-btn:hover::after { - content: '鍥炲埌涓婚〉'; - position: absolute; - top: 35px; - left: 50%; - transform: translateX(-50%); - background-color: #282828; - color: white; - padding: 4px 8px; - border-radius: 4px; - font-size: 14px; - white-space: nowrap; - z-index: 1000; + content: '鍥炲埌涓婚〉'; + position: absolute; + top: 35px; + left: 50%; + transform: translateX(-50%); + background-color: #282828; + color: white; + padding: 4px 8px; + border-radius: 4px; + font-size: 14px; + white-space: nowrap; + z-index: 1000; } .manage-btn { @@ -206,9 +207,9 @@ function callHome() { margin-right: 10px; color: #fff; text-decoration: none; - cursor: pointer; - border-radius: 50%; - transition: width, color, background-color ease-in-out 0.2s; + cursor: pointer; + border-radius: 50%; + transition: width, color, background-color ease-in-out 0.2s; } .manage-btn svg { @@ -218,25 +219,25 @@ function callHome() { } .manage-btn:hover { - transform: translateY(-2px); + transform: translateY(-2px); } /* 娣诲姞鎮仠鏍峰紡 */ .manage-btn:hover::after { - content: '澧炲姞姝屾洸'; - position: absolute; - top: 35px; - left: 50%; - transform: translateX(-50%); - background-color: #282828; - color: white; - padding: 4px 8px; - border-radius: 4px; - font-size: 14px; - white-space: nowrap; - z-index: 1000; + content: '澧炲姞姝屾洸'; + position: absolute; + top: 35px; + left: 50%; + transform: translateX(-50%); + background-color: #282828; + color: white; + padding: 4px 8px; + border-radius: 4px; + font-size: 14px; + white-space: nowrap; + z-index: 1000; } .search-box { @@ -283,39 +284,39 @@ input[type="text"]:focus { } .more-btn { - display: flex; - align-items: center; - margin-right: 10px; - color: #fff; - text-decoration: none; - cursor: pointer; - border-radius: 50%; - transition: width, color, background-color ease-in-out 0.2s; + display: flex; + align-items: center; + margin-right: 10px; + color: #fff; + text-decoration: none; + cursor: pointer; + border-radius: 50%; + transition: width, color, background-color ease-in-out 0.2s; } .more-btn svg { - width: 32px; - height: 32px; - margin-right: 10px; + width: 32px; + height: 32px; + margin-right: 10px; } .more-btn:hover { - transform: scale(1.1); + transform: scale(1.1); } .more-btn:hover::after { - content: '鏇村'; - position: absolute; - top: 32px; - left: 38%; - transform: translateX(-50%); - background-color: #282828; - color: white; - padding: 4px 8px; - border-radius: 4px; - font-size: 14px; - white-space: nowrap; - z-index: 1000; + content: '鏇村'; + position: absolute; + top: 32px; + left: 38%; + transform: translateX(-50%); + background-color: #282828; + color: white; + padding: 4px 8px; + border-radius: 4px; + font-size: 14px; + white-space: nowrap; + z-index: 1000; } .role-icon { @@ -323,9 +324,9 @@ input[type="text"]:focus { opacity: 0; transform: translateX(-20px); /* 鍒濆浣嶇疆绋嶅井鍋忓乏 */ animation: slideIn 0.5s forwards; - cursor: pointer; - border-radius: 50%; - transition: width, color, background-color ease-in-out 0.2s; + cursor: pointer; + border-radius: 50%; + transition: width, color, background-color ease-in-out 0.2s; } .role-icon svg { @@ -336,95 +337,95 @@ input[type="text"]:focus { } .role-icon svg:hover { - transform: translateY(-2px); + transform: translateY(-2px); } .role-icon:hover::after { - content: '涓汉涓婚〉'; - position: absolute; - top: 35px; - left: 50%; - transform: translateX(-50%); - background-color: #282828; - color: white; - padding: 4px 8px; - border-radius: 4px; - font-size: 14px; - white-space: nowrap; - z-index: 1000; + content: '涓汉涓婚〉'; + position: absolute; + top: 35px; + left: 50%; + transform: translateX(-50%); + background-color: #282828; + color: white; + padding: 4px 8px; + border-radius: 4px; + font-size: 14px; + white-space: nowrap; + z-index: 1000; } .set-icon { - margin: 10px 0; - opacity: 0; - transform: translateX(-20px); /* 鍒濆浣嶇疆绋嶅井鍋忓乏 */ - animation: slideIn 0.5s forwards; - cursor: pointer; - border-radius: 50%; - transition: width, color, background-color ease-in-out 0.2s; + margin: 10px 0; + opacity: 0; + transform: translateX(-20px); /* 鍒濆浣嶇疆绋嶅井鍋忓乏 */ + animation: slideIn 0.5s forwards; + cursor: pointer; + border-radius: 50%; + transition: width, color, background-color ease-in-out 0.2s; } .set-icon svg { - color: #d5d5d5; - width: 32px; - height: 32px; - margin-right: 10px; + color: #d5d5d5; + width: 32px; + height: 32px; + margin-right: 10px; } .set-icon svg:hover { - transform: translateY(-2px); + transform: translateY(-2px); } .set-icon:hover::after { - content: '璁剧疆'; - position: absolute; - top: 35px; - left: 38%; - transform: translateX(-50%); - background-color: #282828; - color: white; - padding: 4px 8px; - border-radius: 4px; - font-size: 14px; - white-space: nowrap; - z-index: 1000; + content: '璁剧疆'; + position: absolute; + top: 35px; + left: 38%; + transform: translateX(-50%); + background-color: #282828; + color: white; + padding: 4px 8px; + border-radius: 4px; + font-size: 14px; + white-space: nowrap; + z-index: 1000; } .exit-icon { - margin: 10px 0; - opacity: 0; - transform: translateX(-20px); /* 鍒濆浣嶇疆绋嶅井鍋忓乏 */ - animation: slideIn 0.5s forwards; - cursor: pointer; - border-radius: 50%; - transition: width, color, background-color ease-in-out 0.2s; + margin: 10px 0; + opacity: 0; + transform: translateX(-20px); /* 鍒濆浣嶇疆绋嶅井鍋忓乏 */ + animation: slideIn 0.5s forwards; + cursor: pointer; + border-radius: 50%; + transition: width, color, background-color ease-in-out 0.2s; } .exit-icon svg { - color: #d5d5d5; - width: 32px; - height: 32px; - margin-right: 10px; + color: #d5d5d5; + width: 32px; + height: 32px; + margin-right: 10px; } .exit-icon svg:hover { - color: red; - transform: translateY(-2px); + color: red; + transform: translateY(-2px); } .exit-icon:hover::after { - content: '閫€鍑�'; - color: red; - position: absolute; - top: 35px; - left: 38%; - transform: translateX(-50%); - background-color: #282828; - padding: 4px 8px; - border-radius: 4px; - font-size: 14px; - white-space: nowrap; - z-index: 1000; + content: '閫€鍑�'; + color: red; + position: absolute; + top: 35px; + left: 38%; + transform: translateX(-50%); + background-color: #282828; + padding: 4px 8px; + border-radius: 4px; + font-size: 14px; + white-space: nowrap; + z-index: 1000; } @keyframes slideIn { diff --git a/src/components/LeftSideBar.vue b/src/components/LeftSideBar.vue index 642e1f1..43b3b22 100644 --- a/src/components/LeftSideBar.vue +++ b/src/components/LeftSideBar.vue @@ -5,7 +5,7 @@ import musicAlbumClosed from "../icon/musicAlbumClosed.vue"; import searchIcon from "../icon/searchIcon.vue"; import plusIcon from "../icon/plusIcon.vue"; import playButton from "../icon/playButton.vue"; -import {getPlaylistsByUser} from "../api/playlist"; +import {createPlaylist, getPlaylistsByUser} from "../api/playlist"; import {ElPopover} from "element-plus"; const emit = defineEmits(); @@ -28,39 +28,50 @@ const userToken = ref(JSON.parse(sessionStorage.getItem('user-token'))); const currentUserId = ref(userToken.value.id); function toggleSideBar() { - isSideBarOpen = !isSideBarOpen; - sideBarWidth.value = isSideBarOpen ? criticalWidth : minWidth; + isSideBarOpen = !isSideBarOpen; + sideBarWidth.value = isSideBarOpen ? criticalWidth : minWidth; } function startResizing(event) { - event.preventDefault(); - const initialWidth = sideBarWidth.value; - const initialMouseX = event.clientX; - - const onMouseMove = (moveEvent) => { - sideBarWidth.value = initialWidth + (moveEvent.clientX - initialMouseX); - // 纭繚瀹藉害涓嶅皬浜庢渶灏忓€� - if (sideBarWidth.value <= criticalWidth) { - isSideBarOpen = false; - sideBarWidth.value = minWidth; - } - // 纭繚瀹藉害涓嶅ぇ浜庢渶澶у€� - else if (sideBarWidth.value >= maximumWidth) { - sideBarWidth.value = maximumWidth; - } else - isSideBarOpen = true; - }; - - const onMouseUp = () => { - window.removeEventListener('mousemove', onMouseMove); - window.removeEventListener('mouseup', onMouseUp); - }; - window.addEventListener('mousemove', onMouseMove); - window.addEventListener('mouseup', onMouseUp); + event.preventDefault(); + const initialWidth = sideBarWidth.value; + const initialMouseX = event.clientX; + + const onMouseMove = (moveEvent) => { + sideBarWidth.value = initialWidth + (moveEvent.clientX - initialMouseX); + // 纭繚瀹藉害涓嶅皬浜庢渶灏忓€� + if (sideBarWidth.value <= criticalWidth) { + isSideBarOpen = false; + sideBarWidth.value = minWidth; + } + // 纭繚瀹藉害涓嶅ぇ浜庢渶澶у€� + else if (sideBarWidth.value >= maximumWidth) { + sideBarWidth.value = maximumWidth; + } else + isSideBarOpen = true; + }; + + const onMouseUp = () => { + window.removeEventListener('mousemove', onMouseMove); + window.removeEventListener('mouseup', onMouseUp); + }; + window.addEventListener('mousemove', onMouseMove); + window.addEventListener('mouseup', onMouseUp); } function addAlbum() { - //TODO锛氭坊鍔犳柊鐨勭┖姝屽崟 + console.log("Hi") + createPlaylist({ + user_id: currentUserId.value, + }).then(() => { + getPlaylistsByUser({ + user_id: currentUserId.value + }).then(res => { + musicAlbums.value = res.data.result || [] + }).catch(e => { + + }) + }) } function toggleSearchBar() { @@ -94,7 +105,7 @@ onMounted(() => { const popover1 = ref(null) const closePopover = () => { - popover1.value.hide(); + popover1.value.hide(); } defineProps({ @@ -113,11 +124,11 @@ defineProps({ </div> <el-popover v-if="isSideBarOpen" class="dropdown-options" - ref="popover1" + ref="popover1" :width="200" trigger="click" :hide-after=0 - popper-class="left-popover"> + popper-class="left-popover"> <template #reference> <div class="add-album"> <plus-icon class="plus-icon"/> @@ -142,16 +153,16 @@ defineProps({ @mouseenter="()=>{hoverOnAlbum=true}" @mouseleave="()=>{hoverOnAlbum=false}" :style="{ scrollbarWidth : hoverOnAlbum? 'auto':'none'}" - > - + > + <div v-if="musicAlbums !== undefined" v-for="album in musicAlbums" :key="album.id" @mouseenter="()=>{albumHoveredIndex = album.id}" @mouseleave="()=>{albumHoveredIndex = null}" :style="{backgroundColor: albumHoveredIndex === album.id ? '#1F1F1F' : '#171717' }" - @click="emit('setCurrentPlaylist', album);" - class="musicAlbum-item"> + @click="emit('setCurrentPlaylist', album);" + class="musicAlbum-item"> <img :src="album.picPath" alt="playlist" @@ -163,7 +174,8 @@ defineProps({ <div class="musicAlbum-description"> <p style="padding-bottom: 5px;font-size: 18px">{{ album.title }}</p> - <p v-if="album.title !== '鎴戝枩娆㈢殑姝屾洸'" style="color: #b2b2b2;font-size: 13px">姝屽崟 鈥� {{ userToken.username }}</p> + <p v-if="album.title !== '鎴戝枩娆㈢殑姝屾洸'" style="color: #b2b2b2;font-size: 13px">姝屽崟 鈥� + {{ userToken.username }}</p> <p v-else style="color: #b2b2b2;font-size: 13px">榛樿鏀惰棌澶�</p> </div> </div> @@ -194,7 +206,7 @@ ul { li { color: white; padding: 10px 12px; - border-radius: 10px; + border-radius: 10px; } li:hover { diff --git a/src/components/MainView.vue b/src/components/MainView.vue index 107046c..3fcf7a6 100644 --- a/src/components/MainView.vue +++ b/src/components/MainView.vue @@ -40,7 +40,7 @@ getSongsByPlaylist({ <div v-for="song in songs" :key="song.id" class="song"> - <img :src="song.picPath" alt=""> + <img class="recommend-song-img" :src="song.picPath" alt=""> <h2>{{ song.title }}</h2> <p>{{ song.artist }}</p> </div> @@ -126,4 +126,8 @@ getSongsByPlaylist({ background-color: #fff; color: #000; } + +.recommend-song-img:hover { + transform: rotate(3deg) scale(1.02); +} </style> \ No newline at end of file diff --git a/src/components/MusicAlbumView.vue b/src/components/MusicAlbumView.vue index 9d4ccd8..119b39d 100644 --- a/src/components/MusicAlbumView.vue +++ b/src/components/MusicAlbumView.vue @@ -6,7 +6,7 @@ import checkMark from "../icon/checkMark.vue"; import {ElMessage, ElPopover} from "element-plus"; import {backgroundColor, updateBackground} from "../utils/getBackgroundColor"; import pauseButton from "../icon/pauseButton.vue"; -import {removePlaylist, removeSongFromPlaylist} from "../api/playlist"; +import {modifyPlaylist, removePlaylist, removeSongFromPlaylist} from "../api/playlist"; const emit = defineEmits(); const props = defineProps({ @@ -22,8 +22,9 @@ const props = defineProps({ currentSongId: Number }); -const gradientColor = computed(() => `linear-gradient(to bottom, ${backgroundColor.value} , #1F1F1F 50%)`) - +const edit_title = ref(""); +const edit_description = ref(""); +const edit_cover_path = ref(""); const recMusicList = ref([ { @@ -43,7 +44,7 @@ let musicPlayIndex = ref(null); let musicPauseIndex = ref(null); const resizeObserver = ref(null) - +const gradientColor = computed(() => `linear-gradient(to bottom, ${backgroundColor.value} , #1F1F1F 50%)`) // 鏀剧缉鏃剁殑缁勪欢澶勭悊 const handleResize = () => { @@ -237,6 +238,17 @@ const editAlbumDescription = (albumId) => { editDesc.style.visibility = "visible"; } +const confirmEdit = (albumId) => { + modifyPlaylist({ + id: albumId, + title: edit_title.value, + description: edit_description.value, + picPath: "", + }).then(() => { + + }) +} + const quitEdit = () => { const editDesc = document.querySelector(".edit-desc"); editDesc.style.visibility = "hidden"; @@ -377,18 +389,17 @@ const addRecommendMusic = (musicId) => { </div> </div> <div class="edit-desc-input-name"> - <input data-testid="playlist-edit-details-name-input" id="text-input-c673a65959365e7f" - type="text" - class="edit-desc-input-name-1" placeholder="娣诲姞鍚嶇О" value="鎴戠殑 #9 姝屽崟"> + <input v-model="edit_title" data-testid="playlist-edit-details-name-input" id="text-input-c673a65959365e7f" type="text" class="edit-desc-input-name-1" placeholder="娣诲姞鍚嶇О"> </div> <div class="edit-desc-input-desc"> - <textarea data-testid="playlist-edit-details-description-input" class="edit-desc-input-desc-1" - placeholder="娣诲姞绠€浠�"></textarea> + <textarea v-model="edit_description" data-testid="playlist-edit-details-description-input" class="edit-desc-input-desc-1" placeholder="娣诲姞绠€浠�"/> </div> <div class="edit-desc-button"> - <button data-testid="playlist-edit-details-save-button" data-encore-id="buttonPrimary" - class="edit-desc-button-1 encore-text-body-medium-bold"><span - class="edit-desc-button-1-1">鏀惰棌</span></button> + <button @click="confirmEdit(albumInfo.id)" data-testid="playlist-edit-details-save-button" + data-encore-id="buttonPrimary" + class="edit-desc-button-1 encore-text-body-medium-bold"> + <span class="edit-desc-button-1-1">鏀惰棌</span> + </button> </div> <p class="encore-text encore-text-marginal-bold final-tip" data-encore-id="text">缁х画涓嬩竴姝ワ紝鍒欒〃绀轰綘宸插悓鎰� Spotify 鑾峰彇浣犻€夋嫨涓婁紶鐨勫浘鍍忋€傝纭繚浣犳湁涓婁紶姝ゅ浘鍍忕殑鏉冨埄銆�</p> @@ -415,11 +426,7 @@ const addRecommendMusic = (musicId) => { musicHoveredIndex === music.id ? 'rgba(54,54,54,0.7)' :'rgba(0,0,0,0)', }"> <!--@click浜嬩欢鍐欏湪script涓殑鍑芥暟閲� 鏃犳硶鍙婃椂瑙﹀彂:style涓殑鏍峰紡!!!--> - <div - :style="{visibility: musicHoveredIndex === music.id||musicPlayIndex === music.id ? 'hidden' : 'visible' }"> - {{ - musicList.indexOf(music) + 1 - }} + <div :style="{visibility: musicHoveredIndex === music.id||musicPlayIndex === music.id ? 'hidden' : 'visible' }">{{ musicList.indexOf(music) + 1 }} </div> <play-button @click="playFromId(music.id)" style="position: absolute;left: 14px;cursor: pointer" v-if="(musicHoveredIndex === music.id&&musicPlayIndex!==music.id)||musicPauseIndex===music.id" diff --git a/src/views/HomePage.vue b/src/views/HomePage.vue index b5e1219..76bee64 100644 --- a/src/views/HomePage.vue +++ b/src/views/HomePage.vue @@ -479,7 +479,7 @@ function receiveDataFromHome() { 2 - Comments 3 - Search Results */ -const midComponents = ref(1); +const midComponents = ref(0); const setMidComponents = (val) => { midComponents.value = val; } @@ -592,7 +592,8 @@ let playFromLeftBarAlbum = ref(null); </div> </div> </el-container> - <el-container class="playlist-container" style="overflow: auto; height: 384px; display: flex; flex-direction: column"> + <el-container class="playlist-container" + style="overflow: auto; height: 384px; display: flex; flex-direction: column"> <div v-for="(song, index) in songs" class="playlist-item" style="display: flex; flex-direction: row"> <div @click="switchToSong(index, false)" style="cursor: pointer"> @@ -1698,7 +1699,7 @@ footer { /* 閫€鍑烘悳绱㈠浘鏍� */ .exit-search { position: absolute; - top: 110px; + top: 120px; right: 10px; width: 30px; height: 30px; diff --git a/src/views/a.vue b/src/views/a.vue deleted file mode 100644 index 30e5884..0000000 --- a/src/views/a.vue +++ /dev/null @@ -1,412 +0,0 @@ -<script setup> -import {defineEmits, onMounted, ref} from "vue"; -import musicAlbumOpened from "../icon/musicAlbumOpened.vue"; -import musicAlbumClosed from "../icon/musicAlbumClosed.vue"; -import searchIcon from "../icon/searchIcon.vue"; -import plusIcon from "../icon/plusIcon.vue"; -import playButton from "../icon/playButton.vue"; -import {getPlaylistsByUser} from "../api/playlist"; -import {ElPopover} from "element-plus"; - -const emit = defineEmits(); - -const musicAlbums = ref([]); - -let albumHoveredIndex = ref(null); -let hoverOnAlbum = ref(false); -let isSideBarOpen = ref(true); -let sideBarWidth = ref(250); -let user = ref("HanG"); -const criticalWidth = 180; -const maximumWidth = 310; -const minWidth = 75; - -/* - USER - */ -const userToken = ref(JSON.parse(sessionStorage.getItem('user-token'))); -const currentUserId = ref(userToken.value.id); - -function toggleSideBar() { - isSideBarOpen = !isSideBarOpen; - sideBarWidth.value = isSideBarOpen ? criticalWidth : minWidth; -} - -function startResizing(event) { - event.preventDefault(); - const initialWidth = sideBarWidth.value; - const initialMouseX = event.clientX; - - const onMouseMove = (moveEvent) => { - sideBarWidth.value = initialWidth + (moveEvent.clientX - initialMouseX); - // 纭繚瀹藉害涓嶅皬浜庢渶灏忓€� - if (sideBarWidth.value <= criticalWidth) { - isSideBarOpen = false; - sideBarWidth.value = minWidth; - } - // 纭繚瀹藉害涓嶅ぇ浜庢渶澶у€� - else if (sideBarWidth.value >= maximumWidth) { - sideBarWidth.value = maximumWidth; - } else - isSideBarOpen = true; - }; - - const onMouseUp = () => { - window.removeEventListener('mousemove', onMouseMove); - window.removeEventListener('mouseup', onMouseUp); - }; - window.addEventListener('mousemove', onMouseMove); - window.addEventListener('mouseup', onMouseUp); -} - -function addAlbum() { - //TODO锛氭坊鍔犳柊鐨勭┖姝屽崟 -} - -function toggleSearchBar() { - const input = document.querySelector(".search-input"); - input.classList.toggle('active'); // 鍒囨崲杈撳叆妗嗙殑鏄剧ず鐘舵€� - input.focus(); // 鐐瑰嚮鎼滅储鍥炬爣鍚庤仛鐒﹁緭鍏ユ -} - -function blurSearchBar() { - const input = document.querySelector(".search-input"); - if (input.classList.contains('active')) - input.classList.remove('active'); - -} - -function searchAlbum() { - const input = document.querySelector(".search-input").value; - // TODO:鎻愪氦琛ㄥ崟 -} - -onMounted(() => { - getPlaylistsByUser({ - user_id: currentUserId.value - }).then(res => { - musicAlbums.value = res.data.result || [] - }).catch(e => { - - }) -}) - -defineProps({ - callParentFunction: Function -}) -</script> - -<template> - <nav class="main-menu resizable-box" :style="{ width: sideBarWidth + 'px'}"> - <div class="top-control"> - <div class="toggle-button" @click="toggleSideBar"> - <music-album-opened v-if="isSideBarOpen"/> - <music-album-closed v-if="!isSideBarOpen"/> - <p style="margin-left: 15px;font:normal small-caps bold 20px Arial, sans-serif ;" v-if="isSideBarOpen"> - 闊充箰搴�</p> - </div> - - <el-popover v-if="isSideBarOpen" class="dropdown-options" - :width="200" - trigger="click" - :hide-after=0> - <template #reference> - <div class="add-album"> - <plus-icon class="plus-icon"/> - </div> - </template> - <ul> - <li @click="addAlbum">娣诲姞姝屽崟</li> - </ul> - </el-popover> - - </div> - <div class="search-container"> - <div class="search-album" v-if="isSideBarOpen" @click="toggleSearchBar"> - <search-icon class="search-icon"/> - </div> - <input type="text" class="search-input" placeholder="杈撳叆鎼滅储姝屽崟" @keydown.enter="searchAlbum" - @blur="blurSearchBar"/> - </div> - - - <div class="musicAlbums" - @mouseenter="()=>{hoverOnAlbum=true}" - @mouseleave="()=>{hoverOnAlbum=false}" - :style="{ scrollbarWidth : hoverOnAlbum? 'auto':'none'}"> - - - <div v-if="musicAlbums !== undefined" v-for="album in musicAlbums" - :key="album.id" - @mouseenter="()=>{albumHoveredIndex = album.id}" - @mouseleave="()=>{albumHoveredIndex = null}" - :style="{backgroundColor: albumHoveredIndex === album.id ? '#1F1F1F' : '#171717' }" - class="musicAlbum-item"> - <img - :src="album.picPath" - alt="playlist" - class="musicAlbum-image" - :style="{opacity:albumHoveredIndex === album.id ? 0.4 :1}" - /> - <play-button @click="emit('setCurrentPlaylist', album);" v-if="albumHoveredIndex === album.id" - class="play-button"/> - - <div class="musicAlbum-description"> - <p style="padding-bottom: 5px;font-size: 18px">{{ album.title }}</p> - <p v-if="album.title !== '鎴戝枩娆㈢殑姝屾洸'" style="color: #b2b2b2;font-size: 13px">姝屽崟 鈥� {{ userToken.username }}</p> - <p v-else style="color: #b2b2b2;font-size: 13px">榛樿鏀惰棌澶�</p> - </div> - </div> - </div> - <div class="resizer" @mousedown="startResizing" :style="{left:(sideBarWidth+8) +'px'}"></div> - - </nav> -</template> - -<style scoped> - -*, -*::before, -*::after { - box-sizing: border-box; - padding: 0; - margin: 0; -} - -ul { - background-color: #282828; - list-style-type: none; - margin: 0; - border-radius: 10px; - padding: 12px 8px; -} - -li { - color: white; - padding: 10px 12px; -} - -li:hover { - cursor: pointer; - background-color: #404040; - text-decoration: underline; -} - -nav { - user-select: none; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - -o-user-select: none; -} - - -.main-menu.resizable-box { - /* position: relative; /*浣垮緱瀛愬厓绱犵殑absotute鏄浉瀵逛簬璇ュ厓绱� 杩欓噷涓嶈缃紝浣嶇疆閫氳繃js鎺у埗 涓嶇劧鐨勮瘽resizer浼氳gap閬斀*/ - display: flex; - flex-direction: column; - border: none; - border-radius: 12px; - padding: 12px 0 20px; - overflow: hidden; - font-family: inherit; - background-color: #171717; - -} - -.top-control { - margin-top: 10px; - display: flex; - align-items: center; - justify-content: space-between; -} - -.add-album { - color: #b2b2b2; - margin-top: 5px; - margin-right: 10px; - width: 30px; - cursor: pointer; -} - -.search-container { - margin: 12px 10px; - display: flex; - align-items: center; - cursor: pointer; -} - -.search-icon { - font-size: 24px; - transition: margin-right 0.3s ease; -} - -.search-input { - background-color: #404040; - font-size: 15px; - color: #ffffff; - height: 35px; - border: none; - width: 0; - opacity: 0; - transition: width 0.3s ease, opacity 0.3s ease; - padding: 5px; - border-radius: 4px; - outline: none; -} - -.search-input.active { - width: 70%; /* 璁剧疆杈撳叆妗嗘媺浼稿悗鐨勫搴� */ - opacity: 1; -} - -.search-album { - display: flex; - color: #b2b2b2; - width: 35px; - height: 35px; - cursor: pointer; - align-items: center; - justify-content: center; -} - -.plus-icon { - - border-radius: 50%; - transition: width, color, background-color ease-in-out 0.2s; -} - -.plus-icon:hover { - transform: scale(1.1); - color: #efeeee; - background-color: #404040; -} - -.search-icon { - padding: 3px; - border-radius: 50%; - transition: width, color, background-color ease-in-out 0.2s; -} - -.search-icon:hover { - transform: scale(1.05); - color: #efeeee; - background-color: #404040; -} - -.toggle-button:hover { - color: #efeeee; -} - -.toggle-button { - display: flex; - align-items: center; - width: 120px; - margin: 0 0 0 16px; - background-color: transparent; - cursor: pointer; - transition: color 0.2s ease; - color: #b2b2b2; -} - -.resizer { - - position: absolute; - width: 7px; - background-color: transparent; - height: 92%; - top: 85px; - cursor: ew-resize; /* 姘村钩璋冩暣鍏夋爣 */ - - &::before { - opacity: 0; - position: absolute; - content: ''; - left: 3px; - width: 1px; - height: 100%; - background-color: #9d9d9d; - transition: opacity 0.2s ease-in-out; - } - - &:hover::before { - opacity: 1; - } -} - - -.musicAlbums { - height: 100%; - padding: 0 10px 0 10px; - overflow: auto; - /*榛樿鎯呭喌 婊氬姩鏉℃秷澶�*/ - -} - -/*婊戝姩鏉�*/ -.musicAlbums::-webkit-scrollbar { - width: 12px; /* 婊氬姩鏉″搴� */ -} - -.musicAlbums::-webkit-scrollbar:window-inactive { - -} - -.musicAlbums::-webkit-scrollbar-track { - background: transparent; /* 婊氬姩鏉¤儗鏅� */ -} - -.musicAlbums::-webkit-scrollbar-thumb { - background: #888; /* 婊氬姩鏉¢鑹� */ - border-radius: 10px; /* 鍦嗚 */ - -} - -.musicAlbums::-webkit-scrollbar-thumb:hover { - background-color: #555; /* 鎮仠鏃剁殑棰滆壊 */ -} - -.musicAlbum-item { - display: flex; - position: relative; - align-items: center; - border-radius: 10px; - padding: 10px 0; - color: #f6f6f6; -} - -.musicAlbum-description { - text-align: left; - display: flex; - flex-direction: column; - -} - -.musicAlbum-image { - width: 55px; /* 璋冩暣鍥剧墖澶у皬 */ - height: 55px; /* 璋冩暣鍥剧墖澶у皬 */ - margin-right: 10px; - border-radius: 10px; -} - -.play-button { - position: absolute; - top: 20px; - left: 10px; - color: #f1f1f1; /* 鎾斁閿殑棰滆壊 */ - cursor: pointer; /* 榧犳爣绉诲姩鍒版挱鏀鹃敭涓婃椂鏄剧ず涓虹偣鍑绘墜鍨� */ - transition: transform 0.3s ease; -} - -.play-button:hover { - transform: scale(1.1); -} - -.musicAlbum-description { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; /* 鍗曡鏄剧ず鏂囨湰 */ -} - - -</style> \ No newline at end of file -- GitLab