highlight the selected when you go to folder

This commit is contained in:
geoffrey45 2022-07-09 09:52:46 +03:00
parent 09c588c856
commit 4688665156
9 changed files with 135 additions and 45 deletions

View File

@ -21,8 +21,10 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import Navigation from "@/components/LeftSidebar/Navigation.vue"; import { useRouter, useRoute, RouteLocationNormalized } from "vue-router";
import { onStartTyping } from "@vueuse/core";
import Navigation from "@/components/LeftSidebar/Navigation.vue";
import RightSideBar from "@/components/RightSideBar/Main.vue"; import RightSideBar from "@/components/RightSideBar/Main.vue";
import nowPlaying from "@/components/LeftSidebar/nowPlaying.vue"; import nowPlaying from "@/components/LeftSidebar/nowPlaying.vue";
import NavBar from "@/components/nav/NavBar.vue"; import NavBar from "@/components/nav/NavBar.vue";
@ -33,14 +35,16 @@ import ContextMenu from "@/components/contextMenu.vue";
import Modal from "@/components/modal.vue"; import Modal from "@/components/modal.vue";
import Notification from "@/components/Notification.vue"; import Notification from "@/components/Notification.vue";
import useQStore from "@/stores/queue"; import useQStore from "@/stores/queue";
import useShortcuts from "@/composables/useKeyboard";
import Logo from "@/components/Logo.vue"; import Logo from "@/components/Logo.vue";
import { useRouter } from "vue-router";
import { onStartTyping } from "@vueuse/core"; import useShortcuts from "@/composables/useKeyboard";
import { isSameRoute } from "@/composables/perks";
const context_store = useContextStore(); const context_store = useContextStore();
const queue = useQStore(); const queue = useQStore();
const app_dom = document.getElementById("app"); const app_dom = document.getElementById("app");
const route = useRoute();
const router = useRouter();
queue.readQueue(); queue.readQueue();
useShortcuts(useQStore); useShortcuts(useQStore);
@ -51,7 +55,18 @@ app_dom.addEventListener("click", (e) => {
} }
}); });
useRouter().afterEach(() => { function removeHighlight(route: RouteLocationNormalized) {
setTimeout(() => {
router.push({ name: route.name, params: route.params });
}, 5000);
}
router.afterEach((to, from) => {
const hid = to.query.highlight as string;
if (hid) removeHighlight(to);
if (isSameRoute(to, from)) return;
document.getElementById("acontent")?.scrollTo(0, 0); document.getElementById("acontent")?.scrollTo(0, 0);
}); });

View File

@ -5,11 +5,12 @@
<SongItem <SongItem
v-for="track in getTracks()" v-for="track in getTracks()"
:key="track.trackid" :key="track.trackid"
:song="track" :track="track"
:index="track.index" :index="track.index"
@updateQueue="updateQueue" @updateQueue="updateQueue"
:isPlaying="queue.playing" :isPlaying="queue.playing"
:isCurrent="queue.currentid == track.trackid" :isCurrent="queue.currentid == track.trackid"
:isHighlighted="highlightid == track.trackid"
/> />
</div> </div>
</div> </div>
@ -22,12 +23,14 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { useRoute } from "vue-router"; import { onBeforeRouteUpdate, useRoute } from "vue-router";
import SongItem from "../shared/SongItem.vue"; import SongItem from "../shared/SongItem.vue";
import useQStore from "../../stores/queue"; import { focusElem } from "@/composables/perks";
import { Track } from "../../interfaces"; import { onMounted, onUpdated, ref } from "vue";
import { Track } from "@/interfaces";
import useQStore from "@/stores/queue";
const queue = useQStore(); const queue = useQStore();
@ -39,8 +42,34 @@ const props = defineProps<{
on_album_page?: boolean; on_album_page?: boolean;
}>(); }>();
let route = useRoute().name; const route = useRoute();
const routename = route.name as string;
const highlightid = ref(route.query.highlight as string);
function highlightTrack(trackid: string) {
focusElem(`track-${trackid}`, 400, "center");
}
onBeforeRouteUpdate(async (to, from) => {
const hid = to.query.highlight as string;
highlightid.value = hid as string;
if (hid) {
highlightTrack(hid as string);
}
});
onUpdated(() => {
if (highlightid.value) {
highlightTrack(highlightid.value);
}
});
onMounted(() => {
if (highlightid.value) {
highlightTrack(highlightid.value);
}
});
/** /**
* Plays a clicked track and updates the queue * Plays a clicked track and updates the queue
* *
@ -51,7 +80,7 @@ function updateQueue(track: Track) {
(t: Track) => t.trackid === track.trackid (t: Track) => t.trackid === track.trackid
); );
switch (route) { switch (routename) {
case "FolderView": case "FolderView":
queue.playFromFolder(props.path, props.tracks); queue.playFromFolder(props.path, props.tracks);
queue.play(index); queue.play(index);
@ -118,10 +147,30 @@ function getTracks() {
&::-webkit-scrollbar { &::-webkit-scrollbar {
display: none; display: none;
} }
.context-on { .context-on {
background-color: $gray4; background-color: $gray4;
color: $white !important; color: $white !important;
} }
.highlighted {
color: $white !important;
animation: blinker 1.5s ease 1s;
}
@keyframes blinker {
25% {
background-color: $gray4;
}
50% {
background-color: transparent;
}
75% {
background-color: $gray4;
}
}
} }
} }
</style> </style>

View File

@ -1,39 +1,46 @@
<template> <template>
<div <div
class="songlist-item rounded" class="songlist-item rounded"
:class="[{ current: props.isCurrent }, { 'context-on': context_on }]" :class="[
@dblclick="emitUpdate(props.song)" { current: isCurrent },
{ 'context-on': context_on },
{
highlighted: isHighlighted,
},
]"
v-bind:class="`track-${track.trackid}`"
@dblclick="emitUpdate(track)"
@contextmenu="showContextMenu" @contextmenu="showContextMenu"
> >
<div class="index">{{ props.index }}</div> <div class="index">{{ index }}</div>
<div class="flex"> <div class="flex">
<div @click="emitUpdate(props.song)" class="thumbnail"> <div @click="emitUpdate(track)" class="thumbnail">
<img <img
:src="imguri + props.song.image" :src="imguri + track.image"
alt="" alt=""
class="album-art image rounded" class="album-art image rounded"
/> />
<div <div
class="now-playing-track image" class="now-playing-track image"
v-if="props.isPlaying && props.isCurrent" v-if="isPlaying && isCurrent"
:class="{ active: isPlaying, not_active: !isPlaying }" :class="{ active: isPlaying, not_active: !isPlaying }"
></div> ></div>
</div> </div>
<div @click="emitUpdate(props.song)"> <div @click="emitUpdate(track)">
<span class="ellip title">{{ props.song.title }}</span> <span class="ellip title">{{ track.title }}</span>
</div> </div>
</div> </div>
<div class="song-artists"> <div class="song-artists">
<div class="ellip" v-if="props.song.artists[0] !== ''"> <div class="ellip" v-if="track.artists[0] !== ''">
<span <span
class="artist" class="artist"
v-for="artist in putCommas(props.song.artists)" v-for="artist in putCommas(track.artists)"
:key="artist" :key="artist"
>{{ artist }}</span >{{ artist }}</span
> >
</div> </div>
<div class="ellip" v-else> <div class="ellip" v-else>
<span class="artist">{{ props.song.albumartist }}</span> <span class="artist">{{ track.albumartist }}</span>
</div> </div>
</div> </div>
<router-link <router-link
@ -41,14 +48,14 @@
:to="{ :to="{
name: 'AlbumView', name: 'AlbumView',
params: { params: {
hash: props.song.albumhash, hash: track.albumhash,
}, },
}" }"
> >
{{ props.song.album }} {{ track.album }}
</router-link> </router-link>
<div class="song-duration"> <div class="song-duration">
<div class="text">{{ formatSeconds(props.song.length) }}</div> <div class="text">{{ formatSeconds(track.length) }}</div>
</div> </div>
<div <div
class="options-icon circular" class="options-icon circular"
@ -66,17 +73,17 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { putCommas, formatSeconds } from "@/composables/perks"; import OptionSvg from "@/assets/icons/more.svg";
import { ContextSrc } from "@/composables/enums";
import { formatSeconds, putCommas } from "@/composables/perks";
import useContextStore from "@/stores/context"; import useContextStore from "@/stores/context";
import useModalStore from "@/stores/modal"; import useModalStore from "@/stores/modal";
import useQueueStore from "@/stores/queue"; import useQueueStore from "@/stores/queue";
import { ContextSrc } from "@/composables/enums";
import OptionSvg from "@/assets/icons/more.svg";
import { ref } from "vue"; import { paths } from "@/config";
import trackContext from "@/contexts/track_context"; import trackContext from "@/contexts/track_context";
import { Track } from "@/interfaces"; import { Track } from "@/interfaces";
import { paths } from "@/config"; import { ref } from "vue";
const contextStore = useContextStore(); const contextStore = useContextStore();
@ -88,7 +95,7 @@ const showContextMenu = (e: Event) => {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
const menus = trackContext(props.song, useModalStore, useQueueStore); const menus = trackContext(props.track, useModalStore, useQueueStore);
contextStore.showContextMenu(e, menus, ContextSrc.Track); contextStore.showContextMenu(e, menus, ContextSrc.Track);
context_on.value = true; context_on.value = true;
@ -102,10 +109,11 @@ const showContextMenu = (e: Event) => {
}; };
const props = defineProps<{ const props = defineProps<{
song: Track; track: Track;
index: Number; index: Number;
isPlaying: Boolean; isPlaying: Boolean;
isCurrent: Boolean; isCurrent: Boolean;
isHighlighted: Boolean;
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{

View File

@ -1,3 +1,5 @@
import { RouteLocationNormalized } from "vue-router";
const putCommas = (artists: string[]) => { const putCommas = (artists: string[]) => {
let result = []; let result = [];
@ -12,14 +14,14 @@ const putCommas = (artists: string[]) => {
return result; return result;
}; };
function focusElem(className: string, delay?: number) { function focusElem(className: string, delay?: number, pos?: any) {
const dom = document.getElementsByClassName(className)[0]; const dom = document.getElementsByClassName(className)[0];
setTimeout(() => { setTimeout(() => {
if (dom) { if (dom) {
dom.scrollIntoView({ dom.scrollIntoView({
behavior: "smooth", behavior: "smooth",
block: "start", block: `${pos ?? "start"}` as any,
inline: "center", inline: "center",
}); });
} }
@ -37,6 +39,16 @@ function getElem(id: string, type: string) {
} }
} }
type r = RouteLocationNormalized;
function isSameRoute(to: r, from: r) {
if (to.params.path == from.params.path) {
return true;
}
return false;
}
/** /**
* Converts seconds into minutes and hours. * Converts seconds into minutes and hours.
* @param seconds The seconds to convert * @param seconds The seconds to convert
@ -80,4 +92,4 @@ function formatSeconds(seconds: number, long?: boolean) {
} }
} }
export { putCommas, focusElem, formatSeconds, getElem }; export { putCommas, focusElem, formatSeconds, getElem, isSameRoute };

View File

@ -90,6 +90,7 @@ export default async (
Router.push({ Router.push({
name: "FolderView", name: "FolderView",
params: { path: track.folder }, params: { path: track.folder },
query: { highlight: track.trackid },
}); });
}, },
icon: "folder", icon: "folder",

View File

@ -38,7 +38,7 @@ const props = defineProps<{
/** /**
* Called when the bottom container is raised. * Called when the bottom container is raised.
*/ */
onBottomRaised?: (routeparams?: RouteParams) => void; bottomRaisedCallback?: (routeparams?: RouteParams) => void;
}>(); }>();
let elem: HTMLElement = null; let elem: HTMLElement = null;
@ -56,7 +56,8 @@ onMounted(() => {
onBeforeRouteUpdate((to) => { onBeforeRouteUpdate((to) => {
if (bottomContainerRaised.value) { if (bottomContainerRaised.value) {
props.onBottomRaised(to.params); if (!props.bottomRaisedCallback) return;
props.bottomRaisedCallback(to.params);
} }
}); });
@ -83,7 +84,8 @@ function toggleBottom() {
classlist.add("addbottompadding"); classlist.add("addbottompadding");
if (!bottomRaisedCallbackExecuted) { if (!bottomRaisedCallbackExecuted) {
bottomRaisedCallbackExecuted = true; bottomRaisedCallbackExecuted = true;
props.onBottomRaised(route.params); if (!props.bottomRaisedCallback) return;
props.bottomRaisedCallback(route.params);
} }
return; return;
} }

View File

@ -16,16 +16,21 @@ import FolderList from "@/components/FolderView/FolderList.vue";
import useFStore from "../stores/pages/folder"; import useFStore from "../stores/pages/folder";
import useLoaderStore from "../stores/loader"; import useLoaderStore from "../stores/loader";
import { isSameRoute } from "@/composables/perks";
const loader = useLoaderStore(); const loader = useLoaderStore();
const FStore = useFStore(); const FStore = useFStore();
const scrollable = ref(null); const scrollable = ref(null);
onBeforeRouteUpdate((to) => { onBeforeRouteUpdate((to, from) => {
if (isSameRoute(to, from)) return;
loader.startLoading(); loader.startLoading();
FStore.fetchAll(to.params.path as string) FStore.fetchAll(to.params.path as string)
.then(() => { .then(() => {
console.log("fetched");
scrollable.value.scrollTop = 0; scrollable.value.scrollTop = 0;
}) })
.then(() => { .then(() => {

View File

@ -1,5 +1,5 @@
<template> <template>
<Page :onBottomRaised="fetchAlbumBio"> <Page :bottomRaisedCallback="fetchAlbumBio">
<template #header> <template #header>
<Header :album="album.info" /> <Header :album="album.info" />
</template> </template>
@ -13,14 +13,13 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { onBeforeRouteUpdate, RouteLocationNormalized, RouteParams } from "vue-router";
import useAStore from "@/stores/pages/album"; import useAStore from "@/stores/pages/album";
import { onBeforeRouteUpdate, RouteLocationNormalized, RouteParams } from "vue-router";
import Page from "@/layouts/HeaderContentBottom.vue"; import Page from "@/layouts/HeaderContentBottom.vue";
import Header from "./Header.vue";
import Content from "./Content.vue";
import Bottom from "./Bottom.vue"; import Bottom from "./Bottom.vue";
import { onBeforeUnmount } from "vue"; import Content from "./Content.vue";
import Header from "./Header.vue";
const album = useAStore(); const album = useAStore();

View File

@ -34,7 +34,6 @@ const playlist = usePTrackStore();
onMounted(() => { onMounted(() => {
playlist.fetchArtists(route.params.pid as string); playlist.fetchArtists(route.params.pid as string);
}); });
</script> </script>
<style lang="scss"></style> <style lang="scss"></style>