responsiveness improvements

+ extract track context menu handler into a composable
This commit is contained in:
geoffrey45
2022-08-13 17:10:48 +03:00
parent a32d8fe66c
commit 1f374eeda1
23 changed files with 274 additions and 249 deletions
+15 -6
View File
@@ -1,6 +1,6 @@
#app-grid { #app-grid {
display: grid; display: grid;
grid-template-columns: min-content 1fr min-content; grid-template-columns: min-content 1fr 29rem;
grid-template-rows: max-content 1fr max-content; grid-template-rows: max-content 1fr max-content;
grid-template-areas: grid-template-areas:
"l-sidebar nav search-input" "l-sidebar nav search-input"
@@ -12,6 +12,20 @@
margin: 0 auto; margin: 0 auto;
gap: 1rem; gap: 1rem;
margin: $small auto; margin: $small auto;
@include for-desktop-down {
grid-template-columns: min-content 1fr 26rem;
}
@include tablet-landscape {
grid-template-columns: min-content 1fr;
.r-sidebar,
#tabs,
#gsearch-input {
display: none;
}
}
} }
#acontent { #acontent {
@@ -30,16 +44,11 @@
grid-area: tabs; grid-area: tabs;
height: 3.5rem; height: 3.5rem;
margin-top: -$small; margin-top: -$small;
@include tablet-landscape {
display: none;
}
} }
.r-sidebar { .r-sidebar {
grid-area: r-sidebar; grid-area: r-sidebar;
margin-top: -$small; margin-top: -$small;
width: 29rem;
} }
#gsearch-input { #gsearch-input {
+34
View File
@@ -0,0 +1,34 @@
@mixin ximage {
background-position: center;
background-size: cover;
background-repeat: no-repeat;
}
// media query mixins
@mixin phone-only {
@media (max-width: 599px) {
@content;
}
}
@mixin tablet-portrait {
@media (max-width: 810) {
@content;
}
}
@mixin tablet-landscape {
@media (max-width: 1080px) {
@content;
}
}
@mixin for-desktop-down {
@media (max-width: 1600px) {
@content;
}
}
@mixin for-big-desktop-up {
@media (min-width: 1800px) {
@content;
}
}
+2 -27
View File
@@ -44,36 +44,11 @@ $secondary: $gray5;
$cta: $blue; $cta: $blue;
$danger: $red; $danger: $red;
$track-hover: $gray4; $track-hover: $gray4;
$context: $gray5; $context: $gray;
// SVG COLORS // SVG COLORS
$default: $accent; $default: $accent;
$track-btn-svg: $red; $track-btn-svg: $red;
$side-nav-svg: $red; $side-nav-svg: $red;
// media query mixins
@mixin phone-only {
@media (max-width: 599px) {
@content;
}
}
@mixin tablet-portrait {
@media (max-width: 900px) {
@content;
}
}
@mixin tablet-landscape {
@media (max-width: 1200px) {
@content;
}
}
@mixin for-desktop-down {
@media (max-width: 1280px) {
@content;
}
}
@mixin for-big-desktop-up {
@media (min-width: 1800px) {
@content;
}
}
-5
View File
@@ -1,5 +0,0 @@
@mixin ximage {
background-position: center;
background-size: cover;
background-repeat: no-repeat;
}
+12 -16
View File
@@ -44,14 +44,14 @@ defineProps<{
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
gap: $small; gap: $small;
min-height: 15rem; min-height: 15rem;
}
@include tablet-portrait { @include for-desktop-down {
grid-template-columns: 1fr; grid-template-columns: 1fr !important;
}
@include tablet-landscape { .left {
grid-template-columns: 1fr auto; display: none;
}
}
} }
.left { .left {
@@ -60,16 +60,12 @@ defineProps<{
width: 100%; width: 100%;
margin-right: $small; margin-right: $small;
overflow: hidden; overflow: hidden;
bg-black: solid 1px $gray5; border: solid 1px $gray5;
background-image: linear-gradient(37deg, $gray5 20%, $gray4); background-image: linear-gradient(37deg, $gray5 20%, $gray4);
@include tablet-portrait { // @include for-desktop-down {
display: none; // display: none;
} // }
@include tablet-landscape {
width: 10rem;
}
$rectpos: calc(50% - 5rem); $rectpos: calc(50% - 5rem);
@@ -95,7 +91,7 @@ defineProps<{
height: 7rem; height: 7rem;
bottom: 0; bottom: 0;
left: calc($rectpos + 7rem); left: calc($rectpos + 7rem);
bg-black-radius: 50%; border-radius: 50%;
box-shadow: 0 0 2rem rgb(0, 0, 0); box-shadow: 0 0 2rem rgb(0, 0, 0);
transition: all 0.25s ease-in-out; transition: all 0.25s ease-in-out;
@@ -105,7 +101,7 @@ defineProps<{
} }
} }
.bio { .bio {
bg-black: solid 1px $gray5; border: solid 1px $gray5;
padding: $small; padding: $small;
line-height: 1.5rem; line-height: 1.5rem;
+17 -1
View File
@@ -65,7 +65,7 @@ const emit = defineEmits<{
(event: "resetBottomPadding"): void; (event: "resetBottomPadding"): void;
}>(); }>();
const albumheaderthing = ref<HTMLElement>(null); const albumheaderthing = ref<any>(null);
const imguri = paths.images.thumb; const imguri = paths.images.thumb;
const nav = useNavStore(); const nav = useNavStore();
@@ -121,6 +121,9 @@ useVisibility(albumheaderthing, handleVisibilityState);
justify-content: flex-end; justify-content: flex-end;
.top { .top {
.h {
opacity: 0.75;
}
.title { .title {
font-size: 2.5rem; font-size: 2.5rem;
font-weight: 600; font-weight: 600;
@@ -146,5 +149,18 @@ useVisibility(albumheaderthing, handleVisibilityState);
} }
} }
} }
@include for-desktop-down {
grid-template-columns: 1fr;
.art > img {
height: 6rem;
box-shadow: 0 0 1rem $black;
}
.info > .top > .title {
font-size: 2rem;
}
}
} }
</style> </style>
-2
View File
@@ -24,7 +24,5 @@ defineProps<{
display: grid; display: grid;
grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr)); grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
gap: $medium; gap: $medium;
padding: $small;
background-color: $gray5;
} }
</style> </style>
+20 -4
View File
@@ -1,8 +1,14 @@
<template> <template>
<div class="folder"> <div class="folder">
<div class="table rounded" v-if="tracks.length"> <div class="table rounded" v-if="tracks.length">
<div class="header" v-if="disc && !album.info.is_single"> <div class="header">
<div class="disc-number">Disc {{ disc }}</div> <div class="disc-number" v-if="disc">Disc {{ disc }}</div>
<div class="disc-number" v-if="$route.name === Routes.folder">
In this folder
</div>
<div class="disc-number" v-if="$route.name === Routes.playlist">
&nbsp;
</div>
</div> </div>
<div class="songlist"> <div class="songlist">
<SongItem <SongItem
@@ -13,7 +19,7 @@
@updateQueue="updateQueue" @updateQueue="updateQueue"
:isPlaying="queue.playing" :isPlaying="queue.playing"
:isCurrent="queue.currentid == track.trackid" :isCurrent="queue.currentid == track.trackid"
:isHighlighted="highlightid == track.uniq_hash" :isHighlighted="($route.query.highlight as string) == track.uniq_hash"
/> />
</div> </div>
</div> </div>
@@ -38,6 +44,7 @@ import { onMounted, onUpdated, ref } from "vue";
import { Track } from "@/interfaces"; import { Track } from "@/interfaces";
import useQStore from "@/stores/queue"; import useQStore from "@/stores/queue";
import useAlbumStore from "@/stores/pages/album"; import useAlbumStore from "@/stores/pages/album";
import { Routes } from "@/composables/enums";
const queue = useQStore(); const queue = useQStore();
const album = useAlbumStore(); const album = useAlbumStore();
@@ -54,12 +61,18 @@ const props = defineProps<{
const route = useRoute(); const route = useRoute();
const routename = route.name as string; const routename = route.name as string;
const highlightid = ref(route.query.highlight as string); const highlightid = ref(route.query.highlight as string | null);
function highlightTrack(t_hash: string) { function highlightTrack(t_hash: string) {
focusElem(`track-${t_hash}`, 500, "center"); focusElem(`track-${t_hash}`, 500, "center");
} }
function resetHighlight() {
setTimeout(() => {
highlightid.value = null;
}, 1000);
}
onBeforeRouteUpdate(async (to, from) => { onBeforeRouteUpdate(async (to, from) => {
const h_hash = to.query.highlight as string; const h_hash = to.query.highlight as string;
highlightid.value = h_hash as string; highlightid.value = h_hash as string;
@@ -72,12 +85,14 @@ onBeforeRouteUpdate(async (to, from) => {
onUpdated(() => { onUpdated(() => {
if (highlightid.value) { if (highlightid.value) {
highlightTrack(highlightid.value); highlightTrack(highlightid.value);
resetHighlight();
} }
}); });
onMounted(() => { onMounted(() => {
if (highlightid.value) { if (highlightid.value) {
highlightTrack(highlightid.value); highlightTrack(highlightid.value);
resetHighlight();
} }
}); });
/** /**
@@ -187,6 +202,7 @@ function getTrackList() {
.songlist { .songlist {
scrollbar-width: none; scrollbar-width: none;
&::-webkit-scrollbar { &::-webkit-scrollbar {
display: none; display: none;
} }
+3 -4
View File
@@ -1,7 +1,7 @@
<template> <template>
<div class="r-home"> <div class="r-home">
<UpNext :next="queue.tracklist[queue.next]" :playNext="queue.playNext" /> <UpNext :track="queue.tracklist[queue.next]" :playNext="queue.playNext" />
<Recommendations /> <!-- <Recommendations /> -->
</div> </div>
</template> </template>
@@ -12,8 +12,7 @@
</style> </style>
<script setup lang="ts"> <script setup lang="ts">
import Recommendations from "./Recommendation.vue";
import UpNext from "../Queue/upNext.vue";
import useQStore from "../../../stores/queue"; import useQStore from "../../../stores/queue";
import UpNext from "../Queue/upNext.vue";
const queue = useQStore(); const queue = useQStore();
</script> </script>
+2 -14
View File
@@ -29,14 +29,6 @@ const tabs = useTabStore();
.r-sidebar { .r-sidebar {
width: 100%; width: 100%;
@include phone-only {
display: none;
}
@include tablet-landscape {
display: none;
}
.grid { .grid {
display: flex; display: flex;
position: relative; position: relative;
@@ -44,12 +36,8 @@ const tabs = useTabStore();
.r-content { .r-content {
grid-area: content; grid-area: content;
width: 29rem; overflow: hidden;
// width: 100%; width: 100%;
// @include tablet-landscape {
// display: none;
// }
.r-search { .r-search {
height: 100%; height: 100%;
+11 -14
View File
@@ -1,18 +1,18 @@
<template> <template>
<div class="up-next"> <div class="up-next">
<div class="r-grid"> <div class="r-grid">
<UpNext :next="queue.tracklist[queue.next]" :playNext="queue.playNext" /> <UpNext :track="queue.tracklist[queue.next]" :playNext="queue.playNext" />
<div class="scrollable-r bg-black rounded"> <div class="scrollable-r bg-black rounded">
<QueueActions /> <QueueActions />
<div class="inner"> <div
<TransitionGroup class="inner"
name="queuelist" @mouseenter="setMouseOver(true)"
@mouseenter="setMouseOver(true)" @mouseleave="setMouseOver(false)"
@mouseleave="setMouseOver(false)" >
> <TransitionGroup name="queuelist">
<TrackItem <TrackItem
v-for="(t, index) in queue.tracklist" v-for="(t, index) in queue.tracklist"
:key="t.trackid" :key="index"
:track="t" :track="t"
@playThis="queue.play(index)" @playThis="queue.play(index)"
:isCurrent="index === queue.current" :isCurrent="index === queue.current"
@@ -29,13 +29,13 @@
<script setup lang="ts"> <script setup lang="ts">
import { onUpdated, ref } from "vue"; import { onUpdated, ref } from "vue";
import { focusElem } from "@/utils";
import useQStore from "@/stores/queue"; import useQStore from "@/stores/queue";
import { focusElem } from "@/utils";
import UpNext from "./Queue/upNext.vue";
import TrackItem from "../shared/TrackItem.vue"; import TrackItem from "../shared/TrackItem.vue";
import PlayingFrom from "./Queue/playingFrom.vue"; import PlayingFrom from "./Queue/playingFrom.vue";
import QueueActions from "./Queue/QueueActions.vue"; import QueueActions from "./Queue/QueueActions.vue";
import UpNext from "./Queue/upNext.vue";
const queue = useQStore(); const queue = useQStore();
const mouseover = ref(false); const mouseover = ref(false);
@@ -84,13 +84,10 @@ onUpdated(() => {
position: relative; position: relative;
height: 100%; height: 100%;
display: grid; display: grid;
grid-template-columns: 1fr;
grid-template-rows: max-content 1fr max-content; grid-template-rows: max-content 1fr max-content;
gap: $small; gap: $small;
.left {
display: flex;
gap: $small;
}
.scrollable-r { .scrollable-r {
height: 100%; height: 100%;
@@ -36,6 +36,11 @@ const queue = useQueueStore();
margin: 1rem; margin: 1rem;
margin-bottom: 0; margin-bottom: 0;
.left {
display: flex;
gap: $small;
}
.action { .action {
padding: $smaller; padding: $smaller;
padding-right: $small; padding-right: $small;
+49 -51
View File
@@ -1,21 +1,18 @@
<template> <template>
<div class="main-item bg-black" @click="playNext"> <div
<div class="h">Up Next</div> class="next-track bg-black"
<div class="itemx shadow"> :class="{ contexton: context_on }"
<div @click="playNext"
class="album-art image" @contextmenu.prevent="showMenu"
:style="{ >
backgroundImage: `url(&quot;${imguri + next.image}&quot;)`, <div class="nextup abs">next up</div>
}" <img :src="paths.images.thumb + track.image" class="rounded" />
></div> <div class="tags">
<div class="tags"> <div class="title ellip">{{ track.title }}</div>
<p class="title ellip">{{ next.title }}</p> <div class="artist ellip">
<hr /> <span v-for="artist in putCommas(track.artists)" :key="artist">{{
<p class="artist ellip"> artist
<span v-for="artist in putCommas(next.artists)" :key="artist">{{ }}</span>
artist
}}</span>
</p>
</div> </div>
</div> </div>
</div> </div>
@@ -23,67 +20,68 @@
<script setup lang="ts"> <script setup lang="ts">
import { paths } from "@/config"; import { paths } from "@/config";
import { putCommas } from "@/utils";
import { Track } from "@/interfaces"; import { Track } from "@/interfaces";
import { putCommas } from "@/utils";
const imguri = paths.images.thumb; import { showTrackContextMenu as showContext } from "@/composables/context";
defineProps<{ import { ref } from "vue";
next: Track;
const props = defineProps<{
track: Track;
playNext: () => void; playNext: () => void;
}>(); }>();
const context_on = ref(false);
function showMenu(e: Event) {
showContext(e, props.track, context_on);
}
</script> </script>
<style lang="scss"> <style lang="scss">
.main-item { .next-track {
border-radius: 0.5rem; border-radius: 0.5rem;
position: relative; position: relative;
display: grid;
grid-template-columns: max-content 1fr;
gap: 1rem;
padding: $small;
width: 100%;
cursor: pointer;
&:hover { &:hover {
background-color: $accent; background-color: $gray4;
.h { .h {
background-color: $black; background-color: $black;
} }
} }
.h { .nextup {
position: absolute;
right: $small; right: $small;
bottom: $small; top: 0;
font-size: 0.9rem; font-size: 0.8rem;
background-color: $accent;
padding: $smaller; padding: $smaller;
border-radius: 0.25rem; border-radius: 0.25rem;
font-style: oblique;
opacity: 0.5;
} }
.itemx { img {
display: flex;
align-items: center;
border-radius: 0.5rem;
padding: 0.75rem;
cursor: pointer;
}
.album-art {
width: 4.5rem; width: 4.5rem;
height: 4.5rem; aspect-ratio: 1;
background-image: url(../../assets/images/null.webp); object-fit: contain;
margin: 0 0.5rem 0 0;
border-radius: 0.5rem;
} }
.tags { .tags {
hr { display: flex;
border: none; flex-direction: column;
margin: 0.3rem; align-items: flex-start;
} justify-content: center;
.title { gap: $small;
width: 20rem;
margin: 0;
}
.artist { .artist {
width: 20rem;
margin: 0;
font-size: small; font-size: small;
} }
} }
@@ -27,6 +27,7 @@ import TracksGrid from "./TracksGrid.vue";
position: relative; position: relative;
overflow: hidden; overflow: hidden;
height: 100%; height: 100%;
width: 100%;
.heading { .heading {
padding: $medium; padding: $medium;
+8 -8
View File
@@ -16,17 +16,22 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from "vue"; import { onMounted } from "vue";
import useSearchStore from "../../stores/search"; import useSearchStore from "../../stores/search";
const search = useSearchStore(); const search = useSearchStore();
let input: HTMLInputElement;
onMounted(() => {
input = document.getElementById("ginner") as HTMLInputElement;
});
function focusThis() { function focusThis() {
document.getElementById("ginner").classList.add("focused"); input.classList.add("focused");
} }
function unfocusThis() { function unfocusThis() {
document.getElementById("ginner").classList.remove("focused"); input.classList.remove("focused");
} }
</script> </script>
@@ -34,11 +39,6 @@ function unfocusThis() {
#gsearch-input { #gsearch-input {
display: flex; display: flex;
height: max-content; height: max-content;
// margin-bottom: $smaller;
@include tablet-landscape {
display: none;
}
#ginner { #ginner {
width: 100%; width: 100%;
+4 -4
View File
@@ -22,7 +22,7 @@
v-for="option in context.options" v-for="option in context.options"
:key="option.label" :key="option.label"
:class="[{ critical: option.critical }, option.type]" :class="[{ critical: option.critical }, option.type]"
@click="option.action()" @click="() => option.action && option.action()"
> >
<div class="icon image" :class="option.icon"></div> <div class="icon image" :class="option.icon"></div>
<div class="label ellip">{{ option.label }}</div> <div class="label ellip">{{ option.label }}</div>
@@ -33,7 +33,7 @@
v-for="child in option.children" v-for="child in option.children"
:key="child.label" :key="child.label"
:class="[{ critical: child.critical }, child.type]" :class="[{ critical: child.critical }, child.type]"
@click="child.action()" @click="child.action && child.action()"
> >
<div class="label ellip"> <div class="label ellip">
{{ child.label }} {{ child.label }}
@@ -69,14 +69,14 @@ const context = useContextStore();
display: flex; display: flex;
align-items: center; align-items: center;
cursor: default; cursor: default;
padding: $small; padding: $small 1rem;
position: relative; position: relative;
.more { .more {
height: 1.5rem; height: 1.5rem;
width: 1.5rem; width: 1.5rem;
position: absolute; position: absolute;
right: 0; right: $small;
background-image: url("../assets/icons/expand.svg"); background-image: url("../assets/icons/expand.svg");
} }
+25 -61
View File
@@ -10,9 +10,9 @@
]" ]"
v-bind:class="`track-${track.uniq_hash}`" v-bind:class="`track-${track.uniq_hash}`"
@dblclick="emitUpdate(track)" @dblclick="emitUpdate(track)"
@contextmenu="showContextMenu" @contextmenu.prevent="showMenu"
> >
<div class="index t-center">{{ index }}</div> <div class="index t-center ellip">{{ index }}</div>
<div class="flex"> <div class="flex">
<div @click="emitUpdate(track)" class="thumbnail"> <div @click="emitUpdate(track)" class="thumbnail">
<img <img
@@ -58,17 +58,12 @@
{{ track.album }} {{ track.album }}
</router-link> </router-link>
<div class="song-duration"> <div class="song-duration">
<div class="text">{{ formatSeconds(track.length) }}</div> <div class="text ellip">{{ formatSeconds(track.length) }}</div>
</div> </div>
<div <div
class="options-icon circular" class="options-icon circular"
:class="{ options_button_clicked }" :class="{ options_button_clicked }"
@click=" @click.stop="showMenu"
(e) => {
showContextMenu(e);
options_button_clicked = true;
}
"
> >
<OptionSvg /> <OptionSvg />
</div> </div>
@@ -78,40 +73,17 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from "vue"; import { ref } from "vue";
import useModalStore from "@/stores/modal";
import useQueueStore from "@/stores/queue";
import useContextStore from "@/stores/context";
import trackContext from "@/contexts/track_context";
import OptionSvg from "@/assets/icons/more.svg"; import OptionSvg from "@/assets/icons/more.svg";
import { paths } from "@/config"; import { paths } from "@/config";
import { Track } from "@/interfaces"; import { Track } from "@/interfaces";
import { ContextSrc } from "@/composables/enums";
import { formatSeconds, putCommas } from "@/utils"; import { formatSeconds, putCommas } from "@/utils";
import { showTrackContextMenu as showContext } from "@/composables/context";
const contextStore = useContextStore();
const context_on = ref(false); const context_on = ref(false);
const imguri = paths.images.thumb; const imguri = paths.images.thumb;
const options_button_clicked = ref(false); const options_button_clicked = ref(false);
const showContextMenu = (e: Event) => {
e.preventDefault();
e.stopPropagation();
const menus = trackContext(props.track, useModalStore, useQueueStore);
contextStore.showContextMenu(e, menus, ContextSrc.Track);
context_on.value = true;
contextStore.$subscribe((mutation, state) => {
if (!state.visible) {
context_on.value = false;
options_button_clicked.value = false;
}
});
};
const props = defineProps<{ const props = defineProps<{
track: Track; track: Track;
index?: number; index?: number;
@@ -127,20 +99,32 @@ const emit = defineEmits<{
function emitUpdate(track: Track) { function emitUpdate(track: Track) {
emit("updateQueue", track); emit("updateQueue", track);
} }
function showMenu(e: Event) {
showContext(e, props.track, options_button_clicked);
}
</script> </script>
<style lang="scss"> <style lang="scss">
.songlist-item { .songlist-item {
display: grid; display: grid;
align-items: center;
grid-template-columns: 1.5rem 1.5fr 1fr 1.5fr 2rem 2.5rem; grid-template-columns: 1.5rem 1.5fr 1fr 1.5fr 2rem 2.5rem;
align-items: center;
justify-items: flex-start;
height: 3.75rem; height: 3.75rem;
text-align: left; gap: 1rem;
gap: $small;
user-select: none; user-select: none;
@include tablet-landscape { @include for-desktop-down {
grid-template-columns: 1.5rem 1.5fr 1fr 1fr 2.5rem; grid-template-columns: 1.5rem 1.5fr 1fr 2.5rem;
.song-album {
display: none !important;
}
.song-duration {
display: none !important;
}
} }
@include tablet-portrait { @include tablet-portrait {
@@ -155,12 +139,6 @@ function emitUpdate(track: Track) {
} }
} }
.song-duration {
@include tablet-landscape {
display: none !important;
}
}
.song-album { .song-album {
word-break: break-all; word-break: break-all;
max-width: max-content; max-width: max-content;
@@ -169,10 +147,6 @@ function emitUpdate(track: Track) {
&:hover { &:hover {
text-decoration: underline; text-decoration: underline;
} }
@include tablet-portrait {
display: none;
}
} }
.song-artists { .song-artists {
@@ -181,26 +155,17 @@ function emitUpdate(track: Track) {
.artist { .artist {
cursor: pointer; cursor: pointer;
} }
@include phone-only {
display: none;
}
} }
.index { .index {
color: grey; opacity: 0.5;
font-size: 0.8rem; font-size: 0.8rem;
width: 2rem; width: 100%;
margin-left: $small;
@include phone-only {
display: none;
}
} }
.song-duration { .song-duration {
font-size: 0.9rem; font-size: 0.9rem;
width: 5rem !important;
text-align: left; text-align: left;
} }
@@ -211,7 +176,6 @@ function emitUpdate(track: Track) {
justify-content: center; justify-content: center;
aspect-ratio: 1; aspect-ratio: 1;
width: 2rem; width: 2rem;
margin-right: 1rem;
svg { svg {
transition: all 0.2s ease-in; transition: all 0.2s ease-in;
+5 -25
View File
@@ -8,7 +8,7 @@
}, },
{ contexton: context_on }, { contexton: context_on },
]" ]"
@contextmenu="showContextMenu" @contextmenu.prevent="showMenu"
> >
<div class="album-art"> <div class="album-art">
<img :src="paths.images.thumb + track.image" alt="" class="rounded" /> <img :src="paths.images.thumb + track.image" alt="" class="rounded" />
@@ -35,18 +35,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from "vue"; import { ref } from "vue";
import useModalStore from "@/stores/modal";
import useQueueStore from "@/stores/queue";
import useContextStore from "@/stores/context";
import trackContext from "@/contexts/track_context";
import { paths } from "@/config"; import { paths } from "@/config";
import { putCommas } from "@/utils"; import { putCommas } from "@/utils";
import { Track } from "@/interfaces"; import { Track } from "@/interfaces";
import { ContextSrc } from "@/composables/enums"; import { showTrackContextMenu as showContext } from "@/composables/context";
const contextStore = useContextStore();
const imguri = paths.images.thumb;
const props = defineProps<{ const props = defineProps<{
track: Track; track: Track;
@@ -56,21 +48,9 @@ const props = defineProps<{
const context_on = ref(false); const context_on = ref(false);
const showContextMenu = (e: Event) => { function showMenu(e: Event) {
e.preventDefault(); showContext(e, props.track, context_on);
e.stopPropagation(); }
const menus = trackContext(props.track, useModalStore, useQueueStore);
contextStore.showContextMenu(e, menus, ContextSrc.Track);
context_on.value = true;
contextStore.$subscribe((mutation, state) => {
if (!state.visible) {
context_on.value = false;
}
});
};
const emit = defineEmits<{ const emit = defineEmits<{
(e: "PlayThis"): void; (e: "PlayThis"): void;
+28
View File
@@ -0,0 +1,28 @@
import { Ref } from "vue";
import useModalStore from "@/stores/modal";
import useQueueStore from "@/stores/queue";
import useContextStore from "@/stores/context";
import { ContextSrc } from "./enums";
import { Track } from "@/interfaces";
import trackContext from "@/contexts/track_context";
export const showTrackContextMenu = (
e: Event,
track: Track,
flag: Ref<boolean>
) => {
const menu = useContextStore();
const options = trackContext(track, useModalStore, useQueueStore);
menu.showContextMenu(e, options, ContextSrc.Track);
flag.value = true;
menu.$subscribe((mutation, state) => {
if (!state.visible) {
flag.value = false;
}
});
};
+6 -6
View File
@@ -23,7 +23,7 @@ export default defineStore("context-menu", {
y: 500, y: 500,
normalizedX: false, normalizedX: false,
normalizedY: false, normalizedY: false,
src: "", src: <null | string>"",
}), }),
actions: { actions: {
showContextMenu( showContextMenu(
@@ -41,13 +41,13 @@ export default defineStore("context-menu", {
this.options = options; this.options = options;
}); });
const yo = normalize(e.clientX, e.clientY); const xy = normalize(e.clientX, e.clientY);
this.x = yo.normalX; this.x = xy.normalX;
this.y = yo.normalY; this.y = xy.normalY;
this.normalizedX = yo.normalizedX; this.normalizedX = xy.normalizedX;
this.normalizedY = yo.normalizedY; this.normalizedY = xy.normalizedY;
this.src = src; this.src = src;
}, },
hideContextMenu() { hideContextMenu() {
+8
View File
@@ -27,6 +27,14 @@ const pStore = usePStore();
.grid { .grid {
grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr)); grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
gap: 1rem; gap: 1rem;
@include for-desktop-down {
grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr));
.name {
font-size: 0.9rem;
}
}
} }
} }
</style> </style>
+18
View File
@@ -0,0 +1,18 @@
- Removing track from queue
- Removing track from playlist
- Store album bio to db
- Saving queue as playlist
- Queue context menu
- Play full folder without using the play button
- Multi select track and do something
- Use virtual scroll on queue list
- Fix play next bug
- Play full folder as next
- Append full folder to queue
- Deleting a playlist
- Removing playlist image
- using square image on playlist
- Use bottom bar
- Fix search album and artist grid on 720p
+1 -1
View File
@@ -14,7 +14,7 @@ export default defineConfig({
css: { css: {
preprocessorOptions: { preprocessorOptions: {
scss: { scss: {
additionalData: `@import "@/assets/scss/_variables.scss";`, additionalData: `@import "@/assets/scss/_variables.scss", "@/assets/scss/_mixins.scss";`,
}, },
}, },
}, },