mirror of
https://github.com/tcsenpai/swingmusic.git
synced 2025-06-12 22:17:35 +00:00
remove div nesting on right sidebar
+ rewrite vTooltip to handle updates to tooltip text
This commit is contained in:
parent
90514c8080
commit
c9cd6a8067
@ -16,17 +16,17 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="songlist">
|
<div class="songlist">
|
||||||
<SongItem
|
<SongItem
|
||||||
v-for="track in getTrackList()"
|
v-for="(track, index) in getTrackList()"
|
||||||
:key="track.trackid"
|
:key="track.trackid"
|
||||||
:track="track"
|
:track="track"
|
||||||
:index="track.index"
|
:index="track.index"
|
||||||
@updateQueue="updateQueue"
|
@updateQueue="updateQueue(index)"
|
||||||
:isPlaying="queue.playing"
|
:isPlaying="queue.playing"
|
||||||
:isCurrent="queue.currentid == track.trackid"
|
:isCurrent="queue.currentid == track.trackid"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="copyright" v-if="copyright && copyright()">
|
<div class="copyright" v-if="copyright && copyright">
|
||||||
{{ copyright() }}
|
{{ copyright }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="tracks.length === 0">
|
<div v-else-if="tracks.length === 0">
|
||||||
@ -38,19 +38,16 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { useRoute } from "vue-router";
|
|
||||||
import { useElementSize } from "@vueuse/core";
|
import { useElementSize } from "@vueuse/core";
|
||||||
|
|
||||||
import SongItem from "../shared/SongItem.vue";
|
import SongItem from "../shared/SongItem.vue";
|
||||||
|
|
||||||
import { Routes } from "@/composables/enums";
|
import { Routes } from "@/composables/enums";
|
||||||
import { Track } from "@/interfaces";
|
import { Track } from "@/interfaces";
|
||||||
import useAlbumStore from "@/stores/pages/album";
|
|
||||||
import useQStore from "@/stores/queue";
|
import useQStore from "@/stores/queue";
|
||||||
import { computed } from "@vue/reactivity";
|
import { computed } from "@vue/reactivity";
|
||||||
|
|
||||||
const queue = useQStore();
|
const queue = useQStore();
|
||||||
const album = useAlbumStore();
|
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
tracks: Track[];
|
tracks: Track[];
|
||||||
@ -59,14 +56,15 @@ const props = defineProps<{
|
|||||||
playlistid?: string;
|
playlistid?: string;
|
||||||
on_album_page?: boolean;
|
on_album_page?: boolean;
|
||||||
disc?: string | number;
|
disc?: string | number;
|
||||||
copyright?: (() => string) | null;
|
copyright?: string | null;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const route = useRoute();
|
const emit = defineEmits<{
|
||||||
const routename = route.name as string;
|
(e: "playFromPage", index: number): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
const tracklistElem = ref<HTMLElement | null>(null);
|
const tracklistElem = ref<HTMLElement | null>(null);
|
||||||
const { width, height } = useElementSize(tracklistElem);
|
const { width } = useElementSize(tracklistElem);
|
||||||
|
|
||||||
const brk = {
|
const brk = {
|
||||||
sm: 500,
|
sm: 500,
|
||||||
@ -76,41 +74,8 @@ const brk = {
|
|||||||
const isSmall = computed(() => width.value < brk.sm);
|
const isSmall = computed(() => width.value < brk.sm);
|
||||||
const isMedium = computed(() => width.value > brk.sm && width.value < brk.md);
|
const isMedium = computed(() => width.value > brk.sm && width.value < brk.md);
|
||||||
|
|
||||||
/**
|
function updateQueue(index: number) {
|
||||||
* Plays a clicked track and updates the queue
|
emit("playFromPage", index);
|
||||||
*
|
|
||||||
* @param track Track object
|
|
||||||
*/
|
|
||||||
function updateQueue(track: Track) {
|
|
||||||
const index = props.tracks.findIndex(
|
|
||||||
(t: Track) => t.trackid === track.trackid
|
|
||||||
);
|
|
||||||
|
|
||||||
switch (routename) {
|
|
||||||
case Routes.folder:
|
|
||||||
queue.playFromFolder(props.path || "", props.tracks);
|
|
||||||
queue.play(index);
|
|
||||||
break;
|
|
||||||
case Routes.album:
|
|
||||||
const tindex = album.tracks.findIndex((t) => t.trackid === track.trackid);
|
|
||||||
|
|
||||||
queue.playFromAlbum(
|
|
||||||
track.album || "",
|
|
||||||
track.albumartist || "",
|
|
||||||
track.albumhash || "",
|
|
||||||
album.tracks
|
|
||||||
);
|
|
||||||
queue.play(tindex);
|
|
||||||
break;
|
|
||||||
case Routes.playlist:
|
|
||||||
queue.playFromPlaylist(
|
|
||||||
props.pname || "",
|
|
||||||
props.playlistid || "",
|
|
||||||
props.tracks
|
|
||||||
);
|
|
||||||
queue.play(index);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2,20 +2,18 @@
|
|||||||
<div
|
<div
|
||||||
class="r-sidebar rounded border"
|
class="r-sidebar rounded border"
|
||||||
:style="{
|
:style="{
|
||||||
marginBottom: !settings.use_alt_np ? '-1rem' : '',
|
marginBottom: !settings.show_alt_np ? '-1rem' : '',
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<div class="grid">
|
<div class="r-content">
|
||||||
<div class="r-content">
|
<div class="r-dash" v-if="tabs.current === tabs.tabs.home">
|
||||||
<div class="r-dash" v-if="tabs.current === tabs.tabs.home">
|
<DashBoard />
|
||||||
<DashBoard />
|
</div>
|
||||||
</div>
|
<div class="r-search" v-if="tabs.current === tabs.tabs.search">
|
||||||
<div class="r-search" v-if="tabs.current === tabs.tabs.search">
|
<Search />
|
||||||
<Search />
|
</div>
|
||||||
</div>
|
<div class="r-queue" v-if="tabs.current === tabs.tabs.queue">
|
||||||
<div class="r-queue" v-if="tabs.current === tabs.tabs.queue">
|
<Queue />
|
||||||
<Queue />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -35,28 +33,25 @@ const settings = useSettingsStore();
|
|||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.r-sidebar {
|
.r-sidebar {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
.grid {
|
.r-content {
|
||||||
display: flex;
|
width: 100%;
|
||||||
position: relative;
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
.r-content {
|
.r-search {
|
||||||
grid-area: content;
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.r-dash {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.r-queue {
|
||||||
|
height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
width: 100%;
|
display: grid;
|
||||||
|
grid-template-rows: max-content 1fr;
|
||||||
.r-search {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.r-dash {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.r-queue {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="up-next">
|
<QueueActions />
|
||||||
<div class="r-grid">
|
<div class="scrollable-r">
|
||||||
<div class="scrollable-r rounded">
|
<div class="inner">
|
||||||
<QueueActions />
|
<TrackComponent
|
||||||
<div class="inner">
|
v-for="(t, index) in queue.tracklist"
|
||||||
<TrackComponent
|
:key="index"
|
||||||
v-for="(t, index) in queue.tracklist"
|
:track="t"
|
||||||
:key="index"
|
:index="index + 1"
|
||||||
:track="t"
|
:isPlaying="queue.playing"
|
||||||
:index="index + 1"
|
:isHighlighted="false"
|
||||||
:isPlaying="queue.playing"
|
:isCurrent="index === queue.currentindex"
|
||||||
:isHighlighted="false"
|
/>
|
||||||
:isCurrent="index === queue.currentindex"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -58,32 +54,13 @@ onUpdated(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.up-next {
|
.scrollable-r {
|
||||||
overflow: hidden;
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
.heading {
|
.inner {
|
||||||
position: relative;
|
scrollbar-color: grey transparent;
|
||||||
margin: 0.5rem 0 1rem 0;
|
margin: 1rem 0;
|
||||||
}
|
|
||||||
|
|
||||||
.r-grid {
|
|
||||||
position: relative;
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
.scrollable-r {
|
|
||||||
height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
display: grid;
|
|
||||||
grid-template-rows: max-content 1fr;
|
|
||||||
|
|
||||||
.inner {
|
|
||||||
overflow: scroll;
|
|
||||||
overflow-x: hidden;
|
|
||||||
scrollbar-color: grey transparent;
|
|
||||||
margin: 1rem 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -86,11 +86,11 @@ const props = defineProps<{
|
|||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: "updateQueue", song: Track): void;
|
(e: "updateQueue"): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
function emitUpdate(track: Track) {
|
function emitUpdate(track: Track) {
|
||||||
emit("updateQueue", track);
|
emit("updateQueue");
|
||||||
}
|
}
|
||||||
|
|
||||||
function showMenu(e: Event) {
|
function showMenu(e: Event) {
|
||||||
|
@ -11,13 +11,15 @@ function hideTooltip() {
|
|||||||
tooltip.style.visibility = "hidden";
|
tooltip.style.visibility = "hidden";
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleHover(el: HTMLElement, text: string, isHovered: Ref<boolean>) {
|
function handleHover(el: HTMLElement, text: string, handleOthers = true) {
|
||||||
|
let isHovered = false;
|
||||||
|
|
||||||
el.addEventListener("mouseover", () => {
|
el.addEventListener("mouseover", () => {
|
||||||
isHovered.value = true;
|
isHovered = true;
|
||||||
tooltip.innerText = text;
|
tooltip.innerText = text;
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (isHovered.value) {
|
if (isHovered) {
|
||||||
tooltip.style.visibility = "visible";
|
tooltip.style.visibility = "visible";
|
||||||
|
|
||||||
createPopper(el, tooltip, {
|
createPopper(el, tooltip, {
|
||||||
@ -37,28 +39,32 @@ function handleHover(el: HTMLElement, text: string, isHovered: Ref<boolean>) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, 2000);
|
}, 2000);
|
||||||
|
|
||||||
|
function handleHide() {
|
||||||
|
["mouseout", "click"].forEach((event) => {
|
||||||
|
el.addEventListener(event, () => {
|
||||||
|
isHovered = false;
|
||||||
|
hideTooltip();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleOthers ? handleHide() : null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
let isHovered = ref(false);
|
let isHovered = ref(false);
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
state: {},
|
|
||||||
mounted(el: HTMLElement, binding) {
|
mounted(el: HTMLElement, binding) {
|
||||||
if (tooltip === undefined) {
|
if (tooltip === undefined) {
|
||||||
tooltip = getTooltip();
|
tooltip = getTooltip();
|
||||||
}
|
}
|
||||||
|
|
||||||
handleHover(el, binding.value, isHovered);
|
handleHover(el, binding.value);
|
||||||
["mouseout", "click"].forEach((event) => {
|
|
||||||
el.addEventListener(event, () => {
|
|
||||||
isHovered.value = false;
|
|
||||||
hideTooltip();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
updated(el, binding) {
|
updated(el, binding) {
|
||||||
el.removeEventListener("mouseover", () => {});
|
el.removeEventListener("mouseover", () => {});
|
||||||
handleHover(el, binding.value, isHovered);
|
handleHover(el, binding.value, false);
|
||||||
},
|
},
|
||||||
beforeUnmount(el: HTMLElement) {
|
beforeUnmount(el: HTMLElement) {
|
||||||
hideTooltip();
|
hideTooltip();
|
||||||
|
@ -12,8 +12,12 @@
|
|||||||
loading="lazy"
|
loading="lazy"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<FolderList :folders="FStore.dirs" v-if="FStore.dirs.length" />
|
<FolderList :folders="folder.dirs" v-if="folder.dirs.length" />
|
||||||
<SongList :tracks="FStore.tracks" :path="FStore.path" />
|
<SongList
|
||||||
|
:tracks="folder.tracks"
|
||||||
|
:path="folder.path"
|
||||||
|
@playFromPage="playFromPage"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -26,12 +30,14 @@ import SongList from "@/components/FolderView/SongList.vue";
|
|||||||
import FolderList from "@/components/FolderView/FolderList.vue";
|
import FolderList from "@/components/FolderView/FolderList.vue";
|
||||||
import FolderSvg from "@/assets/icons/folder.svg";
|
import FolderSvg from "@/assets/icons/folder.svg";
|
||||||
|
|
||||||
import useFStore from "../stores/pages/folder";
|
import useFolderStore from "@/stores/pages/folder";
|
||||||
import useLoaderStore from "../stores/loader";
|
import useQueueStore from "@/stores/queue";
|
||||||
|
import useLoaderStore from "@/stores/loader";
|
||||||
import { isSameRoute } from "@/composables/perks";
|
import { isSameRoute } from "@/composables/perks";
|
||||||
|
|
||||||
const loader = useLoaderStore();
|
const loader = useLoaderStore();
|
||||||
const FStore = useFStore();
|
const folder = useFolderStore();
|
||||||
|
const queue = useQueueStore();
|
||||||
|
|
||||||
const scrollable = ref<any>(null);
|
const scrollable = ref<any>(null);
|
||||||
|
|
||||||
@ -40,11 +46,17 @@ function getFolderName(route: RouteLocationNormalized) {
|
|||||||
return path.split("/").pop();
|
return path.split("/").pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function playFromPage(index: number) {
|
||||||
|
queue.playFromFolder(folder.path, folder.tracks);
|
||||||
|
queue.play(index);
|
||||||
|
}
|
||||||
|
|
||||||
onBeforeRouteUpdate((to, from) => {
|
onBeforeRouteUpdate((to, from) => {
|
||||||
if (isSameRoute(to, from)) return;
|
if (isSameRoute(to, from)) return;
|
||||||
|
|
||||||
loader.startLoading();
|
loader.startLoading();
|
||||||
FStore.fetchAll(to.params.path as string)
|
folder
|
||||||
|
.fetchAll(to.params.path as string)
|
||||||
|
|
||||||
.then(() => {
|
.then(() => {
|
||||||
scrollable.value.scrollTop = 0;
|
scrollable.value.scrollTop = 0;
|
||||||
@ -107,7 +119,7 @@ onBeforeRouteUpdate((to, from) => {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
object-position: bottom right;
|
object-position: bottom right;
|
||||||
transition: all .25s ease;
|
transition: all 0.25s ease;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,8 @@
|
|||||||
:tracks="disc"
|
:tracks="disc"
|
||||||
:on_album_page="true"
|
:on_album_page="true"
|
||||||
:disc="key"
|
:disc="key"
|
||||||
:copyright="isLastDisc(key) ? () => copyright : null"
|
:copyright="isLastDisc(key) ? copyright : null"
|
||||||
|
@playFromPage="playFromAlbumPage"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -15,6 +16,8 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Track } from "@/interfaces";
|
import { Track } from "@/interfaces";
|
||||||
import SongList from "@/components/FolderView/SongList.vue";
|
import SongList from "@/components/FolderView/SongList.vue";
|
||||||
|
import useQueueStore from "@/stores/queue";
|
||||||
|
import useAlbumStore from "@/stores/pages/album";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
discs: {
|
discs: {
|
||||||
@ -23,11 +26,20 @@ const props = defineProps<{
|
|||||||
copyright?: string;
|
copyright?: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const queue = useQueueStore();
|
||||||
|
const album = useAlbumStore();
|
||||||
|
|
||||||
// check if the disc is the last disc
|
// check if the disc is the last disc
|
||||||
const isLastDisc = (disc: string | number) => {
|
const isLastDisc = (disc: string | number) => {
|
||||||
const discs = Object.keys(props.discs);
|
const discs = Object.keys(props.discs);
|
||||||
return discs[discs.length - 1] === disc;
|
return discs[discs.length - 1] === disc;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function playFromAlbumPage(index: number) {
|
||||||
|
const { title, artist, hash } = album.info;
|
||||||
|
queue.playFromAlbum(title, artist, hash, album.tracks);
|
||||||
|
queue.play(index);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="songlist rounded">
|
<div class="songlist rounded">
|
||||||
<div v-if="tracks.length">
|
<div v-if="tracks.length">
|
||||||
<SongList :tracks="tracks" :pname="name" :playlistid="playlistid"/>
|
<SongList
|
||||||
|
:tracks="tracks"
|
||||||
|
:pname="name"
|
||||||
|
:playlistid="playlistid"
|
||||||
|
@playFromPage="playFromPlaylistPage"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="tracks.length === 0 && count > 0">
|
<div v-else-if="tracks.length === 0 && count > 0">
|
||||||
<div class="no-results">
|
<div class="no-results">
|
||||||
@ -17,6 +22,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import useQueueStore from "@/stores/queue";
|
||||||
|
import usePlaylistStore from "@/stores/pages/playlist";
|
||||||
|
|
||||||
import SongList from "@/components/FolderView/SongList.vue";
|
import SongList from "@/components/FolderView/SongList.vue";
|
||||||
import { Track } from "@/interfaces";
|
import { Track } from "@/interfaces";
|
||||||
|
|
||||||
@ -26,4 +34,13 @@ defineProps<{
|
|||||||
name: string;
|
name: string;
|
||||||
playlistid: string;
|
playlistid: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const queue = useQueueStore();
|
||||||
|
const playlist = usePlaylistStore();
|
||||||
|
|
||||||
|
function playFromPlaylistPage(index: number) {
|
||||||
|
const { name, playlistid } = playlist.info;
|
||||||
|
queue.playFromPlaylist(name, playlistid, playlist.tracks);
|
||||||
|
queue.play(index);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user