use div scroll method to scroll to current song in queue

This commit is contained in:
geoffrey45
2022-10-01 16:02:51 +03:00
committed by Mungai Njoroge
parent 8e258eaf24
commit 278439eee8
7 changed files with 51 additions and 36 deletions
+1 -1
View File
@@ -4,7 +4,7 @@ input[type="range"] {
width: calc(100% - 2px); width: calc(100% - 2px);
height: 0.3rem; height: 0.3rem;
border-radius: 5px; border-radius: 5px;
background: $gray4 linear-gradient(90deg, $accent, $darkestblue) no-repeat; background: $gray4 linear-gradient(90deg, $darkblue, $darkestblue) no-repeat;
background-size: 100% 100%; background-size: 100% 100%;
&::-webkit-slider-thumb { &::-webkit-slider-thumb {
+1 -1
View File
@@ -30,7 +30,7 @@
</span> </span>
</div> </div>
<div class="tags"> <div class="tags">
<div class="title ellip"> <div v-tooltip class="title ellip">
{{ queue.currenttrack?.title || "Hello there" }} {{ queue.currenttrack?.title || "Hello there" }}
</div> </div>
<ArtistName <ArtistName
+17 -3
View File
@@ -1,13 +1,14 @@
<template> <template>
<QueueActions /> <QueueActions />
<div <div
ref="scrollable"
class="scrollable-r" class="scrollable-r"
v-bind="containerProps" v-bind="containerProps"
style="height: 100%" style="height: 100%"
@mouseover="mouseover = true" @mouseover="mouseover = true"
@mouseout="mouseover = false" @mouseout="mouseover = false"
> >
<div class="inner" v-bind="wrapperProps" > <div class="inner" v-bind="wrapperProps">
<TrackItem <TrackItem
style="height: 64px" style="height: 64px"
v-for="t in tracks" v-for="t in tracks"
@@ -34,6 +35,7 @@ import QueueActions from "./Queue/QueueActions.vue";
const queue = useQStore(); const queue = useQStore();
const mouseover = ref(false); const mouseover = ref(false);
const scrollable = ref<HTMLElement>();
function playFromQueue(index: number) { function playFromQueue(index: number) {
queue.play(index); queue.play(index);
@@ -51,8 +53,8 @@ const {
}); });
onMounted(() => { onMounted(() => {
scrollTo(queue.currentindex); // scrollTo(queue.currentindex);
queue.setScrollFunction(scrollTo, mouseover); queue.setScrollFunction(scrollToCurrent, mouseover);
}); });
onBeforeUnmount(() => { onBeforeUnmount(() => {
@@ -60,6 +62,18 @@ onBeforeUnmount(() => {
}); });
// TODO: Handle focusing current track on song end // TODO: Handle focusing current track on song end
function scrollToCurrent() {
const elem = document.getElementsByClassName('scrollable-r')[0] as HTMLElement;
const itemHeight = 64;
const top = queue.currentindex * itemHeight - itemHeight;
elem.scroll({
top,
behavior: "smooth",
});
}
</script> </script>
<style lang="scss"> <style lang="scss">
-2
View File
@@ -14,9 +14,7 @@
<div class="flex"> <div class="flex">
<div v-auto-animate @click.pre@dblclick.prevent="emitUpdate" class="thumbnail"> <div v-auto-animate @click.pre@dblclick.prevent="emitUpdate" class="thumbnail">
<img <img
loading="lazy"
:src="imguri + track.image" :src="imguri + track.image"
alt=""
class="album-art image rounded-sm" class="album-art image rounded-sm"
/> />
<div <div
-1
View File
@@ -13,7 +13,6 @@
<div class="album-art"> <div class="album-art">
<img <img
:src="paths.images.thumb.small + track.image" :src="paths.images.thumb.small + track.image"
alt=""
class="rounded-sm" class="rounded-sm"
/> />
<div <div
+1 -1
View File
@@ -1,5 +1,5 @@
// "local" | "remote" // "local" | "remote"
let mode = "remote"; let mode = "local";
export interface D<T = string> { export interface D<T = string> {
[key: string]: T; [key: string]: T;
+31 -27
View File
@@ -2,26 +2,27 @@
<!-- JUST A COMMENT: 64 is single item height, 24 is gap height --> <!-- JUST A COMMENT: 64 is single item height, 24 is gap height -->
<div class="header-list-layout"> <div class="header-list-layout">
<div <div
id="v-page-scrollable"
v-bind="containerProps" v-bind="containerProps"
style="height: 100%" style="height: 100%"
:style="{ paddingTop: !no_header ? headerHeight - 64 + 24 + 'px' : 0 }"
@scroll="handleScroll" @scroll="handleScroll"
> >
<div <div
v-bind="wrapperProps" v-bind="wrapperProps"
class="scrollable" class="v-list"
ref="scrollable" ref="v_list"
:class="{ :class="{
isSmall: isSmall, isSmall: isSmall,
isMedium: isMedium || on_album_page, isMedium: isMedium || on_album_page,
}" }"
> >
<div class="header rounded" style="height: 64px" v-if="!no_header"> <div
<div ref="header"
ref="header" class="header rounded"
:style="{ top: -headerHeight + 64 - 24 + 'px' }" v-if="!no_header"
class="header-content" :style="{ height: headerHeight + 24 + 'px' }"
> >
<div ref="header_content" class="header-content">
<slot name="header"></slot> <slot name="header"></slot>
</div> </div>
</div> </div>
@@ -54,7 +55,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { useElementSize, useVirtualList } from "@vueuse/core"; import { useElementSize, useVirtualList } from "@vueuse/core";
import { computed, ref } from "vue"; import { computed, onMounted, onUpdated, ref, watch } from "vue";
import { Track } from "@/interfaces"; import { Track } from "@/interfaces";
import useQStore from "@/stores/queue"; import useQStore from "@/stores/queue";
@@ -79,8 +80,10 @@ function updateQueue(index: number) {
} }
// SCROLLABLE AREA // SCROLLABLE AREA
const scrollable = ref<HTMLElement>(); let scrollable: HTMLElement;
const { width } = useElementSize(scrollable); const v_list = ref<HTMLElement>();
const header_content = ref<HTMLElement>();
const { width } = useElementSize(v_list);
const brk = { const brk = {
sm: 500, sm: 500,
@@ -92,28 +95,38 @@ const isMedium = computed(() => width.value > brk.sm && width.value < brk.md);
// VIRTUAL LIST // VIRTUAL LIST
const source = computed(() => props.tracks); const source = computed(() => props.tracks);
const { const {
list: tracks, list: tracks,
containerProps, containerProps,
wrapperProps, wrapperProps,
} = useVirtualList(source, { } = useVirtualList(source, {
itemHeight: 60, itemHeight: 60,
overscan: 15, overscan: 20,
});
// watch source changes and scroll to top
watch(source, () => {
scrollable.scroll(0, 0);
}); });
// HEADER // HEADER
const header = ref<HTMLElement>(); const header = ref<HTMLElement>();
const { height: headerHeight } = useElementSize(header); const { height: headerHeight } = useElementSize(header_content);
function handleScroll(e: Event) { function handleScroll(e: Event) {
const scrollTop = (e.target as HTMLElement).scrollTop; const scrollTop = (e.target as HTMLElement).scrollTop;
if (scrollTop > headerHeight.value) { if (scrollTop > (header.value?.offsetHeight || 0)) {
header.value ? (header.value.style.opacity = "0") : null; header.value ? (header.value.style.opacity = "0") : null;
} else { } else {
header.value ? (header.value.style.opacity = "1") : null; header.value ? (header.value.style.opacity = "1") : null;
} }
} }
onMounted(() => {
scrollable = document.getElementById("v-page-scrollable") as HTMLElement;
});
</script> </script>
<style lang="scss"> <style lang="scss">
@@ -121,7 +134,7 @@ function handleScroll(e: Event) {
margin-right: -$medium; margin-right: -$medium;
height: 100%; height: 100%;
.scrollable { .v-list {
padding-right: calc(1rem - $small + 2px); padding-right: calc(1rem - $small + 2px);
scrollbar-width: thin; scrollbar-width: thin;
@@ -134,7 +147,7 @@ function handleScroll(e: Event) {
} }
} }
.scrollable.isSmall { .v-list.isSmall {
// hide album and artists columns // hide album and artists columns
.songlist-item { .songlist-item {
grid-template-columns: 1.5rem 2fr 2.5rem 2.5rem; grid-template-columns: 1.5rem 2fr 2.5rem 2.5rem;
@@ -153,7 +166,7 @@ function handleScroll(e: Event) {
} }
} }
.scrollable.isMedium { .v-list.isMedium {
// hide album column // hide album column
.songlist-item { .songlist-item {
grid-template-columns: 1.5rem 1.5fr 1fr 2.5rem 2.5rem; grid-template-columns: 1.5rem 1.5fr 1fr 2.5rem 2.5rem;
@@ -163,14 +176,5 @@ function handleScroll(e: Event) {
display: none !important; display: none !important;
} }
} }
.header {
position: relative;
.header-content {
position: absolute;
width: 100%;
}
}
} }
</style> </style>