mirror of
https://github.com/tcsenpai/swingmusic.git
synced 2025-07-28 13:41:42 +00:00
highlight the selected when you go to folder
This commit is contained in:
parent
09c588c856
commit
4688665156
25
src/App.vue
25
src/App.vue
@ -21,8 +21,10 @@
|
||||
</template>
|
||||
|
||||
<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 nowPlaying from "@/components/LeftSidebar/nowPlaying.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 Notification from "@/components/Notification.vue";
|
||||
import useQStore from "@/stores/queue";
|
||||
import useShortcuts from "@/composables/useKeyboard";
|
||||
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 queue = useQStore();
|
||||
const app_dom = document.getElementById("app");
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
queue.readQueue();
|
||||
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);
|
||||
});
|
||||
|
||||
|
@ -5,11 +5,12 @@
|
||||
<SongItem
|
||||
v-for="track in getTracks()"
|
||||
:key="track.trackid"
|
||||
:song="track"
|
||||
:track="track"
|
||||
:index="track.index"
|
||||
@updateQueue="updateQueue"
|
||||
:isPlaying="queue.playing"
|
||||
:isCurrent="queue.currentid == track.trackid"
|
||||
:isHighlighted="highlightid == track.trackid"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -22,12 +23,14 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useRoute } from "vue-router";
|
||||
import { onBeforeRouteUpdate, useRoute } from "vue-router";
|
||||
|
||||
import SongItem from "../shared/SongItem.vue";
|
||||
|
||||
import useQStore from "../../stores/queue";
|
||||
import { Track } from "../../interfaces";
|
||||
import { focusElem } from "@/composables/perks";
|
||||
import { onMounted, onUpdated, ref } from "vue";
|
||||
import { Track } from "@/interfaces";
|
||||
import useQStore from "@/stores/queue";
|
||||
|
||||
const queue = useQStore();
|
||||
|
||||
@ -39,8 +42,34 @@ const props = defineProps<{
|
||||
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
|
||||
*
|
||||
@ -51,7 +80,7 @@ function updateQueue(track: Track) {
|
||||
(t: Track) => t.trackid === track.trackid
|
||||
);
|
||||
|
||||
switch (route) {
|
||||
switch (routename) {
|
||||
case "FolderView":
|
||||
queue.playFromFolder(props.path, props.tracks);
|
||||
queue.play(index);
|
||||
@ -118,10 +147,30 @@ function getTracks() {
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.context-on {
|
||||
background-color: $gray4;
|
||||
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>
|
||||
|
@ -1,39 +1,46 @@
|
||||
<template>
|
||||
<div
|
||||
class="songlist-item rounded"
|
||||
:class="[{ current: props.isCurrent }, { 'context-on': context_on }]"
|
||||
@dblclick="emitUpdate(props.song)"
|
||||
:class="[
|
||||
{ current: isCurrent },
|
||||
{ 'context-on': context_on },
|
||||
{
|
||||
highlighted: isHighlighted,
|
||||
},
|
||||
]"
|
||||
v-bind:class="`track-${track.trackid}`"
|
||||
@dblclick="emitUpdate(track)"
|
||||
@contextmenu="showContextMenu"
|
||||
>
|
||||
<div class="index">{{ props.index }}</div>
|
||||
<div class="index">{{ index }}</div>
|
||||
<div class="flex">
|
||||
<div @click="emitUpdate(props.song)" class="thumbnail">
|
||||
<div @click="emitUpdate(track)" class="thumbnail">
|
||||
<img
|
||||
:src="imguri + props.song.image"
|
||||
:src="imguri + track.image"
|
||||
alt=""
|
||||
class="album-art image rounded"
|
||||
/>
|
||||
<div
|
||||
class="now-playing-track image"
|
||||
v-if="props.isPlaying && props.isCurrent"
|
||||
v-if="isPlaying && isCurrent"
|
||||
:class="{ active: isPlaying, not_active: !isPlaying }"
|
||||
></div>
|
||||
</div>
|
||||
<div @click="emitUpdate(props.song)">
|
||||
<span class="ellip title">{{ props.song.title }}</span>
|
||||
<div @click="emitUpdate(track)">
|
||||
<span class="ellip title">{{ track.title }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="song-artists">
|
||||
<div class="ellip" v-if="props.song.artists[0] !== ''">
|
||||
<div class="ellip" v-if="track.artists[0] !== ''">
|
||||
<span
|
||||
class="artist"
|
||||
v-for="artist in putCommas(props.song.artists)"
|
||||
v-for="artist in putCommas(track.artists)"
|
||||
:key="artist"
|
||||
>{{ artist }}</span
|
||||
>
|
||||
</div>
|
||||
<div class="ellip" v-else>
|
||||
<span class="artist">{{ props.song.albumartist }}</span>
|
||||
<span class="artist">{{ track.albumartist }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<router-link
|
||||
@ -41,14 +48,14 @@
|
||||
:to="{
|
||||
name: 'AlbumView',
|
||||
params: {
|
||||
hash: props.song.albumhash,
|
||||
hash: track.albumhash,
|
||||
},
|
||||
}"
|
||||
>
|
||||
{{ props.song.album }}
|
||||
{{ track.album }}
|
||||
</router-link>
|
||||
<div class="song-duration">
|
||||
<div class="text">{{ formatSeconds(props.song.length) }}</div>
|
||||
<div class="text">{{ formatSeconds(track.length) }}</div>
|
||||
</div>
|
||||
<div
|
||||
class="options-icon circular"
|
||||
@ -66,17 +73,17 @@
|
||||
</template>
|
||||
|
||||
<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 useModalStore from "@/stores/modal";
|
||||
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 { Track } from "@/interfaces";
|
||||
import { paths } from "@/config";
|
||||
import { ref } from "vue";
|
||||
|
||||
const contextStore = useContextStore();
|
||||
|
||||
@ -88,7 +95,7 @@ const showContextMenu = (e: Event) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
const menus = trackContext(props.song, useModalStore, useQueueStore);
|
||||
const menus = trackContext(props.track, useModalStore, useQueueStore);
|
||||
|
||||
contextStore.showContextMenu(e, menus, ContextSrc.Track);
|
||||
context_on.value = true;
|
||||
@ -102,10 +109,11 @@ const showContextMenu = (e: Event) => {
|
||||
};
|
||||
|
||||
const props = defineProps<{
|
||||
song: Track;
|
||||
track: Track;
|
||||
index: Number;
|
||||
isPlaying: Boolean;
|
||||
isCurrent: Boolean;
|
||||
isHighlighted: Boolean;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { RouteLocationNormalized } from "vue-router";
|
||||
|
||||
const putCommas = (artists: string[]) => {
|
||||
let result = [];
|
||||
|
||||
@ -12,14 +14,14 @@ const putCommas = (artists: string[]) => {
|
||||
return result;
|
||||
};
|
||||
|
||||
function focusElem(className: string, delay?: number) {
|
||||
function focusElem(className: string, delay?: number, pos?: any) {
|
||||
const dom = document.getElementsByClassName(className)[0];
|
||||
|
||||
setTimeout(() => {
|
||||
if (dom) {
|
||||
dom.scrollIntoView({
|
||||
behavior: "smooth",
|
||||
block: "start",
|
||||
block: `${pos ?? "start"}` as any,
|
||||
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.
|
||||
* @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 };
|
||||
|
@ -90,6 +90,7 @@ export default async (
|
||||
Router.push({
|
||||
name: "FolderView",
|
||||
params: { path: track.folder },
|
||||
query: { highlight: track.trackid },
|
||||
});
|
||||
},
|
||||
icon: "folder",
|
||||
|
@ -38,7 +38,7 @@ const props = defineProps<{
|
||||
/**
|
||||
* Called when the bottom container is raised.
|
||||
*/
|
||||
onBottomRaised?: (routeparams?: RouteParams) => void;
|
||||
bottomRaisedCallback?: (routeparams?: RouteParams) => void;
|
||||
}>();
|
||||
|
||||
let elem: HTMLElement = null;
|
||||
@ -56,7 +56,8 @@ onMounted(() => {
|
||||
|
||||
onBeforeRouteUpdate((to) => {
|
||||
if (bottomContainerRaised.value) {
|
||||
props.onBottomRaised(to.params);
|
||||
if (!props.bottomRaisedCallback) return;
|
||||
props.bottomRaisedCallback(to.params);
|
||||
}
|
||||
});
|
||||
|
||||
@ -83,7 +84,8 @@ function toggleBottom() {
|
||||
classlist.add("addbottompadding");
|
||||
if (!bottomRaisedCallbackExecuted) {
|
||||
bottomRaisedCallbackExecuted = true;
|
||||
props.onBottomRaised(route.params);
|
||||
if (!props.bottomRaisedCallback) return;
|
||||
props.bottomRaisedCallback(route.params);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -16,16 +16,21 @@ import FolderList from "@/components/FolderView/FolderList.vue";
|
||||
|
||||
import useFStore from "../stores/pages/folder";
|
||||
import useLoaderStore from "../stores/loader";
|
||||
import { isSameRoute } from "@/composables/perks";
|
||||
|
||||
const loader = useLoaderStore();
|
||||
const FStore = useFStore();
|
||||
|
||||
const scrollable = ref(null);
|
||||
|
||||
onBeforeRouteUpdate((to) => {
|
||||
onBeforeRouteUpdate((to, from) => {
|
||||
if (isSameRoute(to, from)) return;
|
||||
|
||||
loader.startLoading();
|
||||
FStore.fetchAll(to.params.path as string)
|
||||
|
||||
.then(() => {
|
||||
console.log("fetched");
|
||||
scrollable.value.scrollTop = 0;
|
||||
})
|
||||
.then(() => {
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<Page :onBottomRaised="fetchAlbumBio">
|
||||
<Page :bottomRaisedCallback="fetchAlbumBio">
|
||||
<template #header>
|
||||
<Header :album="album.info" />
|
||||
</template>
|
||||
@ -13,14 +13,13 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onBeforeRouteUpdate, RouteLocationNormalized, RouteParams } from "vue-router";
|
||||
import useAStore from "@/stores/pages/album";
|
||||
import { onBeforeRouteUpdate, RouteLocationNormalized, RouteParams } from "vue-router";
|
||||
|
||||
import Page from "@/layouts/HeaderContentBottom.vue";
|
||||
import Header from "./Header.vue";
|
||||
import Content from "./Content.vue";
|
||||
import Bottom from "./Bottom.vue";
|
||||
import { onBeforeUnmount } from "vue";
|
||||
import Content from "./Content.vue";
|
||||
import Header from "./Header.vue";
|
||||
|
||||
const album = useAStore();
|
||||
|
||||
|
@ -34,7 +34,6 @@ const playlist = usePTrackStore();
|
||||
onMounted(() => {
|
||||
playlist.fetchArtists(route.params.pid as string);
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss"></style>
|
||||
|
Loading…
x
Reference in New Issue
Block a user