extract virtual scroller page into a layout

This commit is contained in:
geoffrey45
2022-09-21 14:30:13 +03:00
committed by Mungai Njoroge
parent 76a77823c8
commit 703ea71514
3 changed files with 150 additions and 126 deletions
+36 -15
View File
@@ -1,6 +1,6 @@
<template> <template>
<div class="header-input-wrapper rounded-sm" :class="{ showInput: clicked }"> <div class="header-input-wrapper rounded-sm" :class="{ showInput: clicked }">
<div class="search-svg" @click="clicked = !clicked"> <div class="search-svg" @click="handleFocus">
<SearchSvg /> <SearchSvg />
</div> </div>
<input <input
@@ -8,8 +8,9 @@
class="header-input rounded-sm pad-sm" class="header-input rounded-sm pad-sm"
:class="{ showInput: clicked }" :class="{ showInput: clicked }"
placeholder="Search here" placeholder="Search here"
v-model.trim="source" v-model.trim="query"
id="page-search" id="page-search"
ref="inputRef"
/> />
</div> </div>
</template> </template>
@@ -25,26 +26,44 @@ import useFolderStore from "@/stores/pages/folder";
import { Routes } from "@/composables/enums"; import { Routes } from "@/composables/enums";
import SearchSvg from "@/assets/icons/search.svg"; import SearchSvg from "@/assets/icons/search.svg";
const clicked = ref(false); const clicked = ref(true);
const [playlist, album, folder] = [
usePStore(),
useAlbumStore(),
useFolderStore(),
];
const { query: playlistQuery } = storeToRefs(usePStore()); const { query: playlistQuery } = storeToRefs(playlist);
const { query: folderQuery } = storeToRefs(useFolderStore()); const { query: folderQuery } = storeToRefs(folder);
const { query: albumQuery } = storeToRefs(useAlbumStore()); const { query: albumQuery } = storeToRefs(album);
const props = defineProps<{ const props = defineProps<{
page: Routes | string; page: Routes | string;
}>(); }>();
const inputRef = ref<HTMLElement>();
function handleFocus() {
// if input is not focused, focus it
// if input is focused, blur it
clicked.value = !clicked.value;
if (clicked.value) {
inputRef.value?.focus();
} else {
inputRef.value?.blur();
resetQuery();
}
}
function getRef() { function getRef() {
switch (props.page) { switch (props.page) {
case Routes.playlist: case Routes.playlist:
return playlistQuery; return [playlistQuery, playlist.resetQuery];
case Routes.folder: case Routes.folder:
return folderQuery; return [folderQuery, folder.resetQuery];
case Routes.album: case Routes.album:
return albumQuery; return [albumQuery, album.resetQuery];
default: default:
return null; return null;
@@ -52,6 +71,13 @@ function getRef() {
} }
const source = getRef(); const source = getRef();
let query: any;
let resetQuery: any;
if (source) {
query = source[0];
resetQuery = source[1];
}
</script> </script>
<style lang="scss"> <style lang="scss">
@@ -66,7 +92,6 @@ const source = getRef();
} }
} }
.header-input { .header-input {
background-color: $gray3; background-color: $gray3;
outline: none; outline: none;
@@ -85,24 +110,20 @@ const source = getRef();
&.showInput { &.showInput {
opacity: 1; opacity: 1;
transform: translateY(0); transform: translateY(0);
transition-delay: .1s; transition-delay: 0.1s;
} }
} }
.search-svg { .search-svg {
// outline: solid;
margin-top: $smaller; margin-top: $smaller;
cursor: pointer; cursor: pointer;
// padding-left: ;
width: 2.25rem; width: 2.25rem;
height: 2rem; height: 2rem;
// aspect-ratio: 1;
z-index: 100; z-index: 100;
svg { svg {
display: block; display: block;
margin: 0 auto; margin: 0 auto;
// outline: solid;
} }
} }
</style> </style>
+80
View File
@@ -0,0 +1,80 @@
<template>
<div class="header-list-layout">
<div
v-bind="containerProps"
style="height: calc(100vh - 4.25rem)"
:style="{ paddingTop: headerHeight - 64 + 16 + 'px' }"
@scroll="handleScroll"
>
<div v-bind="wrapperProps">
<div class="header rounded pad-sm" style="height: 64px">
<div
ref="header"
:style="{ top: -headerHeight + 64 - 16 + 'px' }"
class="header-content"
>
<slot name="header"></slot>
</div>
</div>
<SongItem
style="height: 60px"
v-for="(t, index) in tracks"
:key="t.data.trackid"
:track="t.data"
:index="0"
:isPlaying="queue.playing"
:isCurrent="queue.currentid == t.data.trackid"
/>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { useElementSize, useVirtualList } from "@vueuse/core";
import { computed, ref } from "vue";
import { Track } from "@/interfaces";
import useQStore from "@/stores/queue";
import SongItem from "@/components/shared/SongItem.vue";
const props = defineProps<{
tracks: Track[];
}>();
const queue = useQStore();
const header = ref<HTMLElement>();
const source = computed(() => props.tracks);
const { height: headerHeight } = useElementSize(header);
const {
list: tracks,
containerProps,
wrapperProps,
} = useVirtualList(source, {
itemHeight: 60,
overscan: 15,
});
function handleScroll(e: Event) {
const scrollTop = (e.target as HTMLElement).scrollTop;
if (scrollTop > headerHeight.value) {
header.value ? (header.value.style.opacity = "0") : null;
} else {
header.value ? (header.value.style.opacity = "1") : null;
}
}
</script>
<style lang="scss">
.header-list-layout {
.header {
position: relative;
.header-content {
position: absolute;
}
}
}
</style>
+31 -108
View File
@@ -1,133 +1,56 @@
<template> <template>
<div class="queue-view"> <div class="queue-view">
<div <Layout :tracks="queue.tracklist">
v-bind="containerProps" <template #header>
style="height: calc(100vh - 4.25rem)" <div>
:style="{ paddingTop: height - 64 + 16 + 'px' }" Lorem ipsum dolor sit amet consectetur adipisicing elit. Ab doloremque
@scroll="handleScroll" doloribus nostrum voluptas? Nobis ipsa cupiditate perspiciatis earum
> explicabo hic accusamus assumenda commodi, veritatis, nostrum nisi
<div v-bind="wrapperProps"> quod sequi exercitationem ducimus.Lorem ipsum dolor sit amet
<div class="header rounded pad-sm" style="height: 64px"> consectetur, adipisicing elit. Culpa facere recusandae dolorem sunt
<div ref="header" :style="{ top: -height + 64 - 16 + 'px' }"> blanditiis natus delectus alias soluta facilis? Asperiores praesentium
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Culpa repellat magni rerum? Ratione reiciendis ut magni laborum itaque!
facere recusandae dolorem sunt blanditiis natus delectus alias Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequatur,
soluta facilis? Asperiores praesentium repellat magni rerum? Ratione ut. Iure ex nemo sunt. Nostrum, corporis! Asperiores omnis ducimus eum
reiciendis ut magni laborum itaque! Lorem ipsum dolor sit amet culpa quae nesciunt eius, soluta molestiae delectus quasi labore
consectetur adipisicing elit. Consequatur, ut. Iure ex nemo sunt. ex
Nostrum, corporis! Asperiores omnis ducimus eum culpa quae nesciunt nemo sunt. Nostrum, corporis! Asperiores omnis ducimus eum culpa quae
eius, soluta molestiae delectus quasi labore ipsum! Lorem ipsum nesciunt eius, soluta molestiae delectus quasi labore ipsum! Lorem
dolor sit amet consectetur adipisicing elit. Alias et ducimus ipsum dolor sit amet consectetur adipisicing elit. Alias et ducimus
consequuntur doloremque voluptate laboriosam, obcaecati eligendi! consequuntur doloremque voluptate laboriosam, obcaecati eligendi!
Mollitia cum, sint fuga facere sit minus modi quaerat quia nisi, Mollitia cum, sint fuga facere sit minus modi quaerat quia nisi, earum
earum ut! Lorem ipsum dolor sit amet consectetur adipisicing elit. ut! Lorem ipsum dolor sit amet consectetur adipisicing elit. Alias
Alias aliquam, sit laboriosam quidem minus ipsam consequatur aliquam, sit laboriosam quidem minus ipsam consequatur deleniti
deleniti architecto accusamus distinctio earum in suscipit eveniet architecto accusamus distinctio earum in suscipit eveniet temporibus
temporibus obcaecati voluptas odit tenetur adipisci?Lorem ipsum obcaecati voluptas odit tenetur adipisci?
dolor sit amet consectetur, adipisicing elit. Culpa facere
recusandae dolorem sunt blanditiis natus delectus alias soluta
facilis? Asperiores praesentium repellat magni rerum? Ratione
reiciendis ut magni laborum itaque! Lorem ipsum dolor sit amet
consectetur adipisicing elit. Consequatur, ut. Iure ex nemo sunt.
Nostrum, corporis! Asperiores omnis ducimus eum culpa quae nesciunt
eius, soluta molestiae delectus quasi labore ipsum! Lorem ipsum
dolor sit amet consectetur adipisicing elit. Alias et ducimus
consequuntur doloremque voluptate laboriosam, obcaecati eligendi!
Mollitia cum, sint fuga facere sit minus modi quaerat quia nisi,
earum ut! Lorem ipsum dolor sit amet consectetur adipisicing elit.
Alias aliquam, sit laboriosam quidem minus ipsam consequatur
deleniti architecto accusamus distinctio earum in suscipit eveniet
temporibus obcaecati voluptas odit tenetur adipisci?Lorem ipsum
dolor sit amet consectetur, adipisicing elit. Culpa facere
recusandae dolorem sunt blanditiis natus delectus alias soluta
facilis? Asperiores praesentium repellat magni rerum? Ratione
reiciendis ut magni laborum itaque! Lorem ipsum dolor sit amet
consectetur adipisicing elit. Consequatur, ut. Iure ex nemo sunt.
Nostrum, corporis! Asperiores omnis ducimus eum culpa quae nesciunt
eius, soluta molestiae delectus quasi labore ipsum! Lorem ipsum
dolor sit amet consectetur adipisicing elit. Alias et ducimus
consequuntur doloremque voluptate laboriosam, obcaecati eligendi!
Mollitia cum, sint fuga facere sit minus modi quaerat quia nisi,
earum ut! Lorem ipsum dolor sit amet consectetur adipisicing elit.
Alias aliquam, sit laboriosam quidem minus ipsam consequatur
deleniti architecto accusamus distinctio earum in suscipit eveniet
temporibus obcaecati voluptas odit tenetur adipisci?
</div>
</div>
<SongItem
style="height: 60px"
v-for="(t, index) in tracks"
:key="t.data.trackid"
:track="t.data"
:index="0"
:isPlaying="queue.playing"
:isCurrent="queue.currentid == t.data.trackid"
/>
</div>
</div> </div>
</template>
</Layout>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, ref } from "vue"; import { computed, onUpdated, ref } from "vue";
import useQStore from "@/stores/queue"; import useQStore from "@/stores/queue";
import { focusElem } from "@/utils";
import SongList from "@/components/FolderView/SongList.vue";
import { onMounted } from "vue"; import { onMounted } from "vue";
import SongItem from "@/components/shared/SongItem.vue"; import SongItem from "@/components/shared/SongItem.vue";
import { useVirtualList } from "@vueuse/core"; import { useVirtualList } from "@vueuse/core";
import Layout from "@/layouts/HeaderAndVList.vue";
const queue = useQStore(); const queue = useQStore();
const height = ref(330); const height = ref(330);
function playFromQueuePage(index: number) {
queue.play(index);
}
const header = ref<HTMLElement>(); const header = ref<HTMLElement>();
onMounted(() => {
height.value = header.value.offsetHeight;
console.log(height.value);
// height.value = 370;
});
const source = computed(() => queue.tracklist); const source = computed(() => queue.tracklist);
function handleScroll(e: Event) {
// check if header is visible
const headerHeight = header.value?.offsetHeight || 0;
const scrollTop = (e.target as HTMLElement).scrollTop;
if (scrollTop > headerHeight) { // function playFromQueuePage(index: number) {
// console.log("header is not visible"); // queue.play(index);
header.value.style.opacity = "0"; // }
} else { // import SongList from "@/components/FolderView/SongList.vue";
// console.log("header is visible"); // import { focusElem } from "@/utils";
header.value.style.opacity = "1";
}
}
const {
list: tracks,
containerProps,
wrapperProps,
scrollTo,
} = useVirtualList(source, {
itemHeight: 60,
overscan: 15,
});
</script> </script>
<style lang="scss"> <style lang="scss">
.queue-view { .queue-view {
.header {
// background-color: $gray3;
// margin-bottom: 2rem;
position: relative;
overflow: visible;
div {
position: absolute;
top: -25rem;
}
}
} }
</style> </style>