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
+38 -17
View File
@@ -1,6 +1,6 @@
<template>
<div class="header-input-wrapper rounded-sm" :class="{ showInput: clicked }">
<div class="search-svg" @click="clicked = !clicked">
<div class="search-svg" @click="handleFocus">
<SearchSvg />
</div>
<input
@@ -8,8 +8,9 @@
class="header-input rounded-sm pad-sm"
:class="{ showInput: clicked }"
placeholder="Search here"
v-model.trim="source"
v-model.trim="query"
id="page-search"
ref="inputRef"
/>
</div>
</template>
@@ -25,26 +26,44 @@ import useFolderStore from "@/stores/pages/folder";
import { Routes } from "@/composables/enums";
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: folderQuery } = storeToRefs(useFolderStore());
const { query: albumQuery } = storeToRefs(useAlbumStore());
const { query: playlistQuery } = storeToRefs(playlist);
const { query: folderQuery } = storeToRefs(folder);
const { query: albumQuery } = storeToRefs(album);
const props = defineProps<{
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() {
switch (props.page) {
case Routes.playlist:
return playlistQuery;
return [playlistQuery, playlist.resetQuery];
case Routes.folder:
return folderQuery;
return [folderQuery, folder.resetQuery];
case Routes.album:
return albumQuery;
return [albumQuery, album.resetQuery];
default:
return null;
@@ -52,6 +71,13 @@ function getRef() {
}
const source = getRef();
let query: any;
let resetQuery: any;
if (source) {
query = source[0];
resetQuery = source[1];
}
</script>
<style lang="scss">
@@ -66,7 +92,6 @@ const source = getRef();
}
}
.header-input {
background-color: $gray3;
outline: none;
@@ -77,32 +102,28 @@ const source = getRef();
transition: all 0.25s $overshoot;
opacity: 0;
transform: translateY(-1rem);
&:focus {
outline: solid;
}
&.showInput {
opacity: 1;
transform: translateY(0);
transition-delay: .1s;
transition-delay: 0.1s;
}
}
.search-svg {
// outline: solid;
margin-top: $smaller;
cursor: pointer;
// padding-left: ;
width: 2.25rem;
height: 2rem;
// aspect-ratio: 1;
z-index: 100;
svg {
display: block;
margin: 0 auto;
// outline: solid;
}
}
</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>
+32 -109
View File
@@ -1,133 +1,56 @@
<template>
<div class="queue-view">
<div
v-bind="containerProps"
style="height: calc(100vh - 4.25rem)"
:style="{ paddingTop: height - 64 + 16 + 'px' }"
@scroll="handleScroll"
>
<div v-bind="wrapperProps">
<div class="header rounded pad-sm" style="height: 64px">
<div ref="header" :style="{ top: -height + 64 - 16 + 'px' }">
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?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?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>
<Layout :tracks="queue.tracklist">
<template #header>
<div>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Ab doloremque
doloribus nostrum voluptas? Nobis ipsa cupiditate perspiciatis earum
explicabo hic accusamus assumenda commodi, veritatis, nostrum nisi
quod sequi exercitationem ducimus.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
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>
<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>
</template>
</Layout>
</div>
</template>
<script setup lang="ts">
import { computed, ref } from "vue";
import { computed, onUpdated, ref } from "vue";
import useQStore from "@/stores/queue";
import { focusElem } from "@/utils";
import SongList from "@/components/FolderView/SongList.vue";
import { onMounted } from "vue";
import SongItem from "@/components/shared/SongItem.vue";
import { useVirtualList } from "@vueuse/core";
import Layout from "@/layouts/HeaderAndVList.vue";
const queue = useQStore();
const height = ref(330);
function playFromQueuePage(index: number) {
queue.play(index);
}
const header = ref<HTMLElement>();
onMounted(() => {
height.value = header.value.offsetHeight;
console.log(height.value);
// height.value = 370;
});
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) {
// console.log("header is not visible");
header.value.style.opacity = "0";
} else {
// console.log("header is visible");
header.value.style.opacity = "1";
}
}
const {
list: tracks,
containerProps,
wrapperProps,
scrollTo,
} = useVirtualList(source, {
itemHeight: 60,
overscan: 15,
});
// function playFromQueuePage(index: number) {
// queue.play(index);
// }
// import SongList from "@/components/FolderView/SongList.vue";
// import { focusElem } from "@/utils";
</script>
<style lang="scss">
.queue-view {
.header {
// background-color: $gray3;
// margin-bottom: 2rem;
position: relative;
overflow: visible;
div {
position: absolute;
top: -25rem;
}
}
}
</style>