mirror of
https://github.com/Dvorinka/swingmusic-extended.git
synced 2026-06-05 04:53:01 +00:00
rewrite queue page to use songlist
+ add nav components to queue page + revert tooltip to undo handling updates - I can't find a viable solution to the updates problem
This commit is contained in:
@@ -67,6 +67,7 @@ button {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
height: 2.25rem;
|
height: 2.25rem;
|
||||||
background: linear-gradient(70deg, $gray3, $gray2);
|
background: linear-gradient(70deg, $gray3, $gray2);
|
||||||
|
padding: 0 $small;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-image: linear-gradient(70deg, $darkestblue, $darkblue);
|
background-image: linear-gradient(70deg, $darkestblue, $darkblue);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="table"
|
class="table border rounded"
|
||||||
v-if="tracks.length"
|
v-if="tracks.length"
|
||||||
ref="tracklistElem"
|
ref="tracklistElem"
|
||||||
:class="{
|
:class="{
|
||||||
@@ -39,13 +39,13 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { useElementSize } from "@vueuse/core";
|
import { useElementSize } from "@vueuse/core";
|
||||||
|
import { computed } from "@vue/reactivity";
|
||||||
|
|
||||||
import SongItem from "../shared/SongItem.vue";
|
import SongItem from "../shared/SongItem.vue";
|
||||||
|
|
||||||
import { Routes } from "@/composables/enums";
|
import { Routes } from "@/composables/enums";
|
||||||
import { Track } from "@/interfaces";
|
import { Track } from "@/interfaces";
|
||||||
import useQStore from "@/stores/queue";
|
import useQStore from "@/stores/queue";
|
||||||
import { computed } from "@vue/reactivity";
|
|
||||||
|
|
||||||
const queue = useQStore();
|
const queue = useQStore();
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
<span>Shuffle</span>
|
<span>Shuffle</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="right"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -37,20 +36,11 @@ const queue = useQueueStore();
|
|||||||
}
|
}
|
||||||
|
|
||||||
.action {
|
.action {
|
||||||
padding: $smaller;
|
padding-left: $smaller;
|
||||||
padding-right: $small;
|
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
transform: scale(0.8);
|
transform: scale(0.8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-more {
|
|
||||||
padding-right: $smaller;
|
|
||||||
|
|
||||||
svg {
|
|
||||||
transform: scale(1.25);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
<Folder v-if="$route.name == Routes.folder" :subPaths="subPaths" />
|
<Folder v-if="$route.name == Routes.folder" :subPaths="subPaths" />
|
||||||
<SearchTitle v-if="$route.name == Routes.search" />
|
<SearchTitle v-if="$route.name == Routes.search" />
|
||||||
<PlaylistsTitle v-if="$route.name == Routes.playlists" />
|
<PlaylistsTitle v-if="$route.name == Routes.playlists" />
|
||||||
|
<QueueTitle v-if="$route.name == Routes.queue" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!--
|
<!--
|
||||||
@@ -23,21 +24,24 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import NavButtons from "./NavButtons.vue";
|
|
||||||
import Loader from "../shared/Loader.vue";
|
|
||||||
import { useRoute } from "vue-router";
|
|
||||||
import { ref, watch } from "vue";
|
import { ref, watch } from "vue";
|
||||||
import { Routes } from "@/composables/enums";
|
import { useRoute } from "vue-router";
|
||||||
import { createSubPaths } from "@/utils";
|
import { computed } from "@vue/reactivity";
|
||||||
|
|
||||||
import { subPath } from "@/interfaces";
|
import { subPath } from "@/interfaces";
|
||||||
|
import useNavStore from "@/stores/nav";
|
||||||
|
import { createSubPaths } from "@/utils";
|
||||||
|
import { Routes } from "@/composables/enums";
|
||||||
|
|
||||||
|
import NavButtons from "./NavButtons.vue";
|
||||||
|
// import Loader from "../shared/Loader.vue";
|
||||||
|
|
||||||
import Folder from "./Titles/Folder.vue";
|
import Folder from "./Titles/Folder.vue";
|
||||||
import SimpleTitle from "./Titles/SimpleTitle.vue";
|
import SimpleTitle from "./Titles/SimpleTitle.vue";
|
||||||
import APTitle from "./Titles/APTitle.vue";
|
import APTitle from "./Titles/APTitle.vue";
|
||||||
import useNavStore from "@/stores/nav";
|
|
||||||
|
|
||||||
import { computed } from "@vue/reactivity";
|
|
||||||
import SearchTitle from "./Titles/SearchTitle.vue";
|
import SearchTitle from "./Titles/SearchTitle.vue";
|
||||||
import PlaylistsTitle from "./Titles/PlaylistsTitle.vue";
|
import PlaylistsTitle from "./Titles/PlaylistsTitle.vue";
|
||||||
|
import QueueTitle from "./Titles/QueueTitle.vue";
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const nav = useNavStore();
|
const nav = useNavStore();
|
||||||
@@ -53,7 +57,7 @@ const showAPTitle = computed(() => {
|
|||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => route.name,
|
() => route.name,
|
||||||
(newRoute: string) => {
|
(newRoute) => {
|
||||||
switch (newRoute) {
|
switch (newRoute) {
|
||||||
case Routes.folder:
|
case Routes.folder:
|
||||||
let oldpath = "";
|
let oldpath = "";
|
||||||
@@ -90,6 +94,7 @@ watch(
|
|||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: max-content 1fr;
|
grid-template-columns: max-content 1fr;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
|
height: 2.25rem;
|
||||||
|
|
||||||
.info {
|
.info {
|
||||||
margin: auto 0;
|
margin: auto 0;
|
||||||
|
|||||||
@@ -20,18 +20,17 @@ import ArrowSvg from "../../assets/icons/right-arrow.svg";
|
|||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
padding-right: 1.25rem;
|
padding-right: 1.25rem;
|
||||||
border-right: 1px solid $gray3;
|
border-right: 1px solid $gray3;
|
||||||
width: 100%;
|
width: max-content;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
& > * {
|
& > * {
|
||||||
|
width: 2.25rem;
|
||||||
background-color: $gray3;
|
background-color: $gray3;
|
||||||
padding: $small;
|
|
||||||
height: 100%;
|
|
||||||
aspect-ratio: 1;
|
aspect-ratio: 1;
|
||||||
border-radius: $medium;
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
svg {
|
align-items: center;
|
||||||
margin: auto;
|
padding: 0;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.back {
|
.back {
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ const things = computed(() => {
|
|||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
let thing = {
|
let thing = {
|
||||||
text: "",
|
text: "",
|
||||||
store: null,
|
store: null as any,
|
||||||
source: playSources.album,
|
source: playSources.album,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -38,7 +38,6 @@ const things = computed(() => {
|
|||||||
store: usePStore,
|
store: usePStore,
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return thing;
|
return thing;
|
||||||
|
|||||||
@@ -0,0 +1,113 @@
|
|||||||
|
<template>
|
||||||
|
<div class="nav-queue-title">
|
||||||
|
<div class="first noscroll">
|
||||||
|
<router-link :to="(getSourceUrlParams())">
|
||||||
|
<button>Go to source</button>
|
||||||
|
</router-link>
|
||||||
|
<div class="playing-from">
|
||||||
|
<div class="border rounded-sm pad-sm">
|
||||||
|
<b class="ellip">{{ getSourceName() }}</b>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<QueueActions />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import QueueActions from "@/components/RightSideBar/Queue/QueueActions.vue";
|
||||||
|
import { FromOptions, Routes } from "@/composables/enums";
|
||||||
|
import useQueueStore from "@/stores/queue";
|
||||||
|
import { RouteLocationRaw, RouteRecordRaw } from "vue-router";
|
||||||
|
|
||||||
|
const queue = useQueueStore();
|
||||||
|
|
||||||
|
const { from: source } = queue;
|
||||||
|
|
||||||
|
function getSourceName(): RouteLocationRaw {
|
||||||
|
switch (source.type) {
|
||||||
|
case FromOptions.album:
|
||||||
|
return source.name;
|
||||||
|
|
||||||
|
case FromOptions.folder:
|
||||||
|
return source.name;
|
||||||
|
|
||||||
|
case FromOptions.playlist:
|
||||||
|
return source.name;
|
||||||
|
|
||||||
|
case FromOptions.search:
|
||||||
|
return `Search for: "${source.query}"`;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return "Ghost source";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSourceUrlParams() {
|
||||||
|
switch (source.type) {
|
||||||
|
case FromOptions.album:
|
||||||
|
return {
|
||||||
|
name: Routes.album,
|
||||||
|
params: {
|
||||||
|
hash: source.hash,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
case FromOptions.folder:
|
||||||
|
return {
|
||||||
|
name: Routes.folder,
|
||||||
|
params: {
|
||||||
|
path: source.path,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
case FromOptions.playlist:
|
||||||
|
return {
|
||||||
|
name: Routes.playlist,
|
||||||
|
params: {
|
||||||
|
pid: source.playlistid,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
case FromOptions.search:
|
||||||
|
return {
|
||||||
|
name: Routes.search,
|
||||||
|
params: {
|
||||||
|
query: source.query,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
default:
|
||||||
|
return "/";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.nav-queue-title {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr max-content;
|
||||||
|
gap: 1rem;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.first {
|
||||||
|
width: 100%;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: max-content 1fr;
|
||||||
|
gap: 1rem;
|
||||||
|
|
||||||
|
.playing-from {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: $small;
|
||||||
|
opacity: 0.75;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.queue-actions {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -24,9 +24,7 @@ defineProps<{
|
|||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.play-btn {
|
.play-btn {
|
||||||
height: 100%;
|
|
||||||
aspect-ratio: 1;
|
aspect-ratio: 1;
|
||||||
display: grid;
|
padding: 0;
|
||||||
place-items: center;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -76,7 +76,6 @@ const imguri = paths.images.thumb;
|
|||||||
const options_button_clicked = ref(false);
|
const options_button_clicked = ref(false);
|
||||||
|
|
||||||
const artisttitle = ref<HTMLElement | null>(null);
|
const artisttitle = ref<HTMLElement | null>(null);
|
||||||
const tooltip = ref<HTMLElement | null>(null);
|
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
track: Track;
|
track: Track;
|
||||||
@@ -107,13 +106,14 @@ function showMenu(e: Event) {
|
|||||||
height: 3.75rem;
|
height: 3.75rem;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
// background-color: $gray;
|
||||||
|
|
||||||
|
// &:nth-child(odd) {
|
||||||
|
// background-color: rgba(26, 26, 26, 0.068);
|
||||||
|
// }
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: $gray4;
|
background-color: $gray4;
|
||||||
|
|
||||||
.options-icon {
|
|
||||||
opacity: 1 !important;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.song-album {
|
.song-album {
|
||||||
@@ -138,7 +138,6 @@ function showMenu(e: Event) {
|
|||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
// margin-left: $small;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.song-duration {
|
.song-duration {
|
||||||
@@ -151,7 +150,6 @@ function showMenu(e: Event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.options-icon {
|
.options-icon {
|
||||||
opacity: 0;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -160,7 +158,7 @@ function showMenu(e: Event) {
|
|||||||
|
|
||||||
svg {
|
svg {
|
||||||
transition: all 0.2s ease-in;
|
transition: all 0.2s ease-in;
|
||||||
transform: rotate(90deg);
|
// transform: rotate(90deg);
|
||||||
stroke: $track-btn-svg;
|
stroke: $track-btn-svg;
|
||||||
|
|
||||||
circle {
|
circle {
|
||||||
|
|||||||
+11
-24
@@ -1,4 +1,4 @@
|
|||||||
import { Directive, Ref, ref } from "vue";
|
import { Directive } from "vue";
|
||||||
import { createPopper } from "@popperjs/core";
|
import { createPopper } from "@popperjs/core";
|
||||||
|
|
||||||
let tooltip: HTMLElement;
|
let tooltip: HTMLElement;
|
||||||
@@ -11,15 +11,20 @@ function hideTooltip() {
|
|||||||
tooltip.style.visibility = "hidden";
|
tooltip.style.visibility = "hidden";
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleHover(el: HTMLElement, text: string, handleOthers = true) {
|
export default {
|
||||||
|
mounted(el, binding) {
|
||||||
let isHovered = false;
|
let isHovered = false;
|
||||||
|
|
||||||
|
if (tooltip === undefined) {
|
||||||
|
tooltip = getTooltip();
|
||||||
|
}
|
||||||
|
|
||||||
el.addEventListener("mouseover", () => {
|
el.addEventListener("mouseover", () => {
|
||||||
isHovered = true;
|
isHovered = true;
|
||||||
tooltip.innerText = text;
|
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (isHovered) {
|
if (isHovered) {
|
||||||
|
tooltip.innerText = binding.value;
|
||||||
tooltip.style.visibility = "visible";
|
tooltip.style.visibility = "visible";
|
||||||
|
|
||||||
createPopper(el, tooltip, {
|
createPopper(el, tooltip, {
|
||||||
@@ -38,33 +43,15 @@ function handleHover(el: HTMLElement, text: string, handleOthers = true) {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, 2000);
|
}, 1500);
|
||||||
|
});
|
||||||
|
|
||||||
function handleHide() {
|
|
||||||
["mouseout", "click"].forEach((event) => {
|
["mouseout", "click"].forEach((event) => {
|
||||||
el.addEventListener(event, () => {
|
document.addEventListener(event, () => {
|
||||||
isHovered = false;
|
isHovered = false;
|
||||||
hideTooltip();
|
hideTooltip();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
handleOthers ? handleHide() : null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let isHovered = ref(false);
|
|
||||||
|
|
||||||
export default {
|
|
||||||
mounted(el: HTMLElement, binding) {
|
|
||||||
if (tooltip === undefined) {
|
|
||||||
tooltip = getTooltip();
|
|
||||||
}
|
|
||||||
|
|
||||||
handleHover(el, binding.value);
|
|
||||||
},
|
|
||||||
updated(el, binding) {
|
|
||||||
el.removeEventListener("mouseover", () => {});
|
|
||||||
handleHover(el, binding.value, false);
|
|
||||||
},
|
},
|
||||||
beforeUnmount(el: HTMLElement) {
|
beforeUnmount(el: HTMLElement) {
|
||||||
hideTooltip();
|
hideTooltip();
|
||||||
|
|||||||
+22
-6
@@ -1,16 +1,32 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="queue-view">
|
<div class="queue-view">
|
||||||
<Queue :isOnQueuePage="true" />
|
<SongList :tracks="queue.tracklist" @playFromPage="playFromQueuePage" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Queue from "@/components/RightSideBar/Queue.vue";
|
import useQStore from "@/stores/queue";
|
||||||
|
import { focusElem } from "@/utils";
|
||||||
|
import SongList from "@/components/FolderView/SongList.vue";
|
||||||
|
import { onMounted } from "vue";
|
||||||
|
|
||||||
|
const queue = useQStore();
|
||||||
|
|
||||||
|
function playFromQueuePage(index: number) {
|
||||||
|
queue.play(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
focusElem("current");
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<!-- <style lang="scss">
|
||||||
.queue-view {
|
.queue-view {
|
||||||
background-color: $black;
|
.table {
|
||||||
height: 100%;
|
margin-top: -1rem;
|
||||||
}
|
}
|
||||||
</style>
|
}
|
||||||
|
</style> -->
|
||||||
|
|||||||
Reference in New Issue
Block a user