mirror of
https://github.com/tcsenpai/swingmusic.git
synced 2025-06-06 03:05:35 +00:00
use third-party module to auto-persist queue store
+ more redesign + convert js files to ts
This commit is contained in:
parent
5476575d10
commit
03219166c5
@ -16,6 +16,6 @@
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
16
src/App.vue
16
src/App.vue
@ -4,11 +4,13 @@
|
||||
<Notification />
|
||||
<div id="app-grid">
|
||||
<div class="l-sidebar rounded">
|
||||
<Logo />
|
||||
<Navigation />
|
||||
<div class="l-album-art">
|
||||
<nowPlaying />
|
||||
<div class="withlogo">
|
||||
<Logo />
|
||||
<Navigation />
|
||||
</div>
|
||||
|
||||
<nowPlaying />
|
||||
<!-- <Playlists /> -->
|
||||
</div>
|
||||
<NavBar />
|
||||
<div id="acontent" class="rounded">
|
||||
@ -44,6 +46,7 @@ import SearchInput from "@/components/RightSideBar/SearchInput.vue";
|
||||
import BottomBar from "@/components/BottomBar/BottomBar.vue";
|
||||
|
||||
import { readLocalStorage, writeLocalStorage } from "@/utils";
|
||||
import Playlists from "./components/LeftSidebar/Playlists.vue";
|
||||
|
||||
const queue = useQStore();
|
||||
const router = useRouter();
|
||||
@ -94,6 +97,11 @@ onMounted(() => {
|
||||
.l-sidebar {
|
||||
position: relative;
|
||||
|
||||
|
||||
.withlogo {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.l-album-art {
|
||||
width: calc(100% - 2rem);
|
||||
position: absolute;
|
||||
|
@ -62,10 +62,12 @@
|
||||
}
|
||||
|
||||
.l-sidebar {
|
||||
width: 17rem;
|
||||
width: 15rem;
|
||||
grid-area: l-sidebar;
|
||||
display: grid;
|
||||
grid-template-rows: 1fr max-content;
|
||||
gap: 1rem;
|
||||
background-color: $black;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.b-bar {
|
||||
|
@ -45,7 +45,7 @@
|
||||
|
||||
.bg-black {
|
||||
background-color: $gray4;
|
||||
box-shadow: 0 0 1rem rgba(0, 0, 0, 0.1);
|
||||
box-shadow: 0 0 1rem rgba(0, 0, 0, 0.425)
|
||||
}
|
||||
|
||||
.heading {
|
||||
|
@ -4,11 +4,15 @@
|
||||
<img
|
||||
:src="paths.images.thumb + queue.currenttrack?.image"
|
||||
alt=""
|
||||
class="rounded"
|
||||
class="rounded shadow-lg"
|
||||
/>
|
||||
<div class="tags">
|
||||
<div class="np-artist ellip">
|
||||
<span v-for="artist in putCommas(queue.currenttrack?.artists || ['Artist'])">
|
||||
<span
|
||||
v-for="artist in putCommas(
|
||||
queue.currenttrack?.artists || ['Artist']
|
||||
)"
|
||||
>
|
||||
{{ artist }}
|
||||
</span>
|
||||
</div>
|
||||
@ -18,16 +22,27 @@
|
||||
</div>
|
||||
</div>
|
||||
<Progress />
|
||||
<!-- <div class="ex-hotkeys">
|
||||
<HotKeys />
|
||||
</div> -->
|
||||
<div class="time">
|
||||
<span class="current">{{ formatSeconds(queue.currentTime) }}</span>
|
||||
<HotKeys />
|
||||
<span class="full">{{
|
||||
formatSeconds(queue.fullTime || queue.currenttrack.length)
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import "@/assets/scss/BottomBar/BottomBar.scss";
|
||||
import { formatSeconds, putCommas } from "@/utils";
|
||||
import HotKeys from "../LeftSidebar/NP/HotKeys.vue";
|
||||
import Progress from "../LeftSidebar/NP/Progress.vue";
|
||||
|
||||
import useQStore from "@/stores/queue";
|
||||
import { paths } from "@/config";
|
||||
import useQStore from "@/stores/queue";
|
||||
|
||||
const queue = useQStore();
|
||||
</script>
|
||||
@ -36,10 +51,28 @@ const queue = useQStore();
|
||||
.b-bar {
|
||||
display: grid;
|
||||
grid-template-rows: 1fr max-content;
|
||||
border-radius: 1rem;
|
||||
gap: 1rem;
|
||||
padding: 1rem;
|
||||
padding-bottom: 2rem;
|
||||
padding-bottom: 1rem;
|
||||
position: relative;
|
||||
|
||||
.time {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
align-items: center;
|
||||
|
||||
.full {
|
||||
text-align: end;
|
||||
}
|
||||
}
|
||||
|
||||
.ex-hotkeys {
|
||||
position: absolute;
|
||||
width: 10rem;
|
||||
right: 1rem;
|
||||
top: 1rem;
|
||||
border-radius: $small;
|
||||
}
|
||||
|
||||
.info {
|
||||
display: grid;
|
||||
@ -55,11 +88,11 @@ const queue = useQStore();
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
gap: $smaller;
|
||||
|
||||
.np-title {
|
||||
font-size: 1.15rem;
|
||||
font-weight: bold;
|
||||
margin-bottom: $small;
|
||||
}
|
||||
|
||||
.np-artist {
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
|
||||
<div class="hotkeys">
|
||||
<div class="hotkeys rounded noscroll">
|
||||
<div class="image ctrl-btn" id="previous" @click="q.playPrev"></div>
|
||||
<div
|
||||
class="image ctrl-btn play-pause"
|
||||
@ -28,13 +28,13 @@ const q = useQStore();
|
||||
justify-content: center;
|
||||
place-content: flex-end;
|
||||
width: 100%;
|
||||
background-color: $gray2;
|
||||
|
||||
.ctrl-btn {
|
||||
height: 2.5rem;
|
||||
width: 100%;
|
||||
background-size: 1.5rem !important;
|
||||
cursor: pointer;
|
||||
border-radius: 0.5rem;
|
||||
|
||||
&:hover {
|
||||
background-color: $accent;
|
||||
|
@ -1,47 +1,44 @@
|
||||
<template>
|
||||
<div class="info">
|
||||
<div class="desc">
|
||||
<div>
|
||||
<router-link
|
||||
:to="{
|
||||
name: 'AlbumView',
|
||||
params: {
|
||||
hash: track?.albumhash ? track.albumhash : ' ',
|
||||
},
|
||||
}"
|
||||
>
|
||||
<div class="art">
|
||||
<img
|
||||
:src="imguri + track?.image"
|
||||
alt=""
|
||||
class="l-image rounded force-lm"
|
||||
loading="lazy"
|
||||
/>
|
||||
</div>
|
||||
</router-link>
|
||||
|
||||
<div class="sidebar-songcard">
|
||||
<router-link
|
||||
:to="{
|
||||
name: 'AlbumView',
|
||||
params: {
|
||||
hash: track?.albumhash ? track.albumhash : ' ',
|
||||
},
|
||||
}"
|
||||
>
|
||||
<div class="art">
|
||||
<img
|
||||
:src="imguri + track?.image"
|
||||
alt=""
|
||||
class="l-image rounded force-lm"
|
||||
loading="lazy"
|
||||
/>
|
||||
<div id="bitrate" v-if="track?.bitrate">
|
||||
<span v-if="track.bitrate > 1500">MASTER</span>
|
||||
<span v-else-if="track.bitrate > 330">FLAC</span>
|
||||
<span v-else>MP3</span>
|
||||
• {{ track.bitrate }}
|
||||
</div>
|
||||
<div class="title ellip">{{ props.track?.title }}</div>
|
||||
<div class="separator no-border"></div>
|
||||
<div
|
||||
class="artists ellip"
|
||||
v-if="track?.artists && track?.artists[0] !== ''"
|
||||
>
|
||||
<span v-for="artist in putCommas(track.artists)" :key="artist">{{
|
||||
artist
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="artists" v-else-if="track?.artists">
|
||||
<span>{{ track.albumartist }}</span>
|
||||
</div>
|
||||
<div class="artists" v-else>
|
||||
<span>Meh</span>
|
||||
</div>
|
||||
</div>
|
||||
</router-link>
|
||||
|
||||
<div class="bottom">
|
||||
<div class="title ellip">{{ props.track?.title }}</div>
|
||||
<div
|
||||
class="artists ellip"
|
||||
v-if="track?.artists && track?.artists[0] !== ''"
|
||||
>
|
||||
<span v-for="artist in putCommas(track.artists)" :key="artist">{{
|
||||
artist
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="artists" v-else-if="track?.artists">
|
||||
<span>{{ track.albumartist }}</span>
|
||||
</div>
|
||||
<div class="artists" v-else>
|
||||
<span>Meh</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -57,3 +54,53 @@ const props = defineProps<{
|
||||
track: Track | null;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.sidebar-songcard {
|
||||
.art {
|
||||
width: 100%;
|
||||
aspect-ratio: 1;
|
||||
place-items: center;
|
||||
margin-bottom: $small;
|
||||
position: relative;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
aspect-ratio: 1;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
#bitrate {
|
||||
position: absolute;
|
||||
font-size: 0.75rem;
|
||||
width: max-content;
|
||||
padding: 0.2rem 0.35rem;
|
||||
bottom: 1rem;
|
||||
left: 1rem;
|
||||
background-color: $black;
|
||||
border-radius: $smaller;
|
||||
box-shadow: 0rem 0rem 1rem rgba(0, 0, 0, 0.438);
|
||||
}
|
||||
}
|
||||
|
||||
.bottom {
|
||||
display: grid;
|
||||
gap: $smaller;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-weight: 900;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.artists {
|
||||
font-size: 0.85rem;
|
||||
opacity: 0.75;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline 1px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
54
src/components/LeftSidebar/Playlists.vue
Normal file
54
src/components/LeftSidebar/Playlists.vue
Normal file
@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<div class="sidebar-playlists">
|
||||
<div class="header">your playlists</div>
|
||||
<div class="list rounded">
|
||||
<div v-for="p in pStore.playlists" class="ellip">
|
||||
<router-link
|
||||
:to="{
|
||||
name: 'PlaylistView',
|
||||
params: {
|
||||
pid: p.playlistid,
|
||||
},
|
||||
}"
|
||||
>
|
||||
{{ p.name }}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import usePStore from "@/stores/pages/playlists";
|
||||
import { onMounted } from "vue";
|
||||
const pStore = usePStore();
|
||||
|
||||
onMounted(() => {
|
||||
if (pStore.playlists.length == 0) {
|
||||
pStore.fetchAll();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.sidebar-playlists {
|
||||
// outline: solid 1px;
|
||||
display: grid;
|
||||
grid-template-rows: max-content 1fr;
|
||||
|
||||
.header {
|
||||
opacity: 0.5;
|
||||
margin-bottom: $small;
|
||||
margin-left: 1rem;
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
.list {
|
||||
padding: $small;
|
||||
|
||||
& > * {
|
||||
padding: $small;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,14 +1,5 @@
|
||||
<template>
|
||||
<div class="now-playing-card t-center rounded">
|
||||
<div class="headin">Now playing</div>
|
||||
<div
|
||||
class="button menu rounded"
|
||||
@click="showContextMenu"
|
||||
:class="{ context_on: context_on }"
|
||||
>
|
||||
<MenuSvg />
|
||||
</div>
|
||||
<div class="separator no-border"></div>
|
||||
<div>
|
||||
<SongCard :track="queue.currenttrack" />
|
||||
<div class="l-track-time">
|
||||
@ -16,8 +7,8 @@
|
||||
><span class="rounded">{{ formatSeconds(queue.duration.full) }}</span>
|
||||
</div>
|
||||
<Progress />
|
||||
<HotKeys />
|
||||
</div>
|
||||
<HotKeys />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -65,10 +56,11 @@ const showContextMenu = (e: Event) => {
|
||||
<style lang="scss">
|
||||
.now-playing-card {
|
||||
padding: 1rem;
|
||||
background-color: $primary;
|
||||
width: 100%;
|
||||
display: grid;
|
||||
grid-template-rows: 1fr max-content;
|
||||
position: relative;
|
||||
gap: 1rem;
|
||||
|
||||
.l-track-time {
|
||||
display: flex;
|
||||
@ -96,24 +88,6 @@ const showContextMenu = (e: Event) => {
|
||||
}
|
||||
}
|
||||
|
||||
.headin {
|
||||
font-weight: bold;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.button {
|
||||
position: absolute;
|
||||
top: $small;
|
||||
cursor: pointer;
|
||||
transition: all 200ms;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: $smaller;
|
||||
|
||||
&:hover {
|
||||
background-color: $accent;
|
||||
}
|
||||
}
|
||||
|
||||
.context_on {
|
||||
background-color: $accent;
|
||||
@ -123,43 +97,5 @@ const showContextMenu = (e: Event) => {
|
||||
right: $small;
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.art {
|
||||
width: 100%;
|
||||
aspect-ratio: 1;
|
||||
place-items: center;
|
||||
margin-bottom: $small;
|
||||
|
||||
.l-image {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
#bitrate {
|
||||
position: absolute;
|
||||
font-size: 0.75rem;
|
||||
width: max-content;
|
||||
padding: 0.2rem 0.35rem;
|
||||
top: 14rem;
|
||||
left: 2rem;
|
||||
background-color: $black;
|
||||
border-radius: $smaller;
|
||||
box-shadow: 0rem 0rem 1rem rgba(0, 0, 0, 0.438);
|
||||
}
|
||||
|
||||
.title {
|
||||
font-weight: 900;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.artists {
|
||||
font-size: 0.85rem;
|
||||
color: rgba(255, 255, 255, 0.808);
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline 1px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -16,7 +16,6 @@
|
||||
|
||||
#logo {
|
||||
height: 4.5rem !important;
|
||||
width: 15rem;
|
||||
background-image: url(./../assets/images/logo.webp);
|
||||
background-size: contain;
|
||||
@include ximage;
|
||||
|
@ -1,7 +1,6 @@
|
||||
<template>
|
||||
<div class="up-next">
|
||||
<div class="r-grid">
|
||||
<UpNext :track="queue.tracklist[queue.next]" :playNext="queue.playNext" />
|
||||
<div class="scrollable-r bg-black rounded">
|
||||
<QueueActions />
|
||||
<div
|
||||
@ -23,7 +22,6 @@
|
||||
</TransitionGroup>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <PlayingFrom :from="queue.from" /> -->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -35,9 +33,7 @@ import useQStore from "@/stores/queue";
|
||||
import { focusElem } from "@/utils";
|
||||
|
||||
import TrackItem from "../shared/TrackItem.vue";
|
||||
import PlayingFrom from "./Queue/playingFrom.vue";
|
||||
import QueueActions from "./Queue/QueueActions.vue";
|
||||
import UpNext from "./Queue/upNext.vue";
|
||||
|
||||
const queue = useQStore();
|
||||
const mouseover = ref(false);
|
||||
@ -66,8 +62,6 @@ onUpdated(() => {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* ensure leaving items are taken out of layout flow so that moving
|
||||
animations can be calculated correctly. */
|
||||
.queuelist-leave-active {
|
||||
transition: none;
|
||||
position: absolute;
|
||||
@ -85,10 +79,9 @@ onUpdated(() => {
|
||||
.r-grid {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-rows: max-content 1fr;
|
||||
gap: 1rem;
|
||||
// display: grid;
|
||||
|
||||
// gap: 1rem;
|
||||
|
||||
.scrollable-r {
|
||||
height: 100%;
|
||||
|
@ -2,13 +2,16 @@ import "./assets/scss/index.scss";
|
||||
|
||||
import { createPinia } from "pinia";
|
||||
import { createApp } from "vue";
|
||||
import piniaPluginPersistedstate from "pinia-plugin-persistedstate";
|
||||
|
||||
import App from "./App.vue";
|
||||
import router from "./router";
|
||||
|
||||
const app = createApp(App);
|
||||
const pinia = createPinia();
|
||||
pinia.use(piniaPluginPersistedstate);
|
||||
|
||||
app.use(createPinia());
|
||||
app.use(pinia);
|
||||
app.use(router);
|
||||
|
||||
app.mount("#app");
|
@ -1,5 +1,3 @@
|
||||
// @ts-strict
|
||||
|
||||
import { defineStore } from "pinia";
|
||||
import state from "../composables/state";
|
||||
import { NotifType, useNotifStore } from "./notification";
|
||||
@ -14,29 +12,6 @@ import {
|
||||
Track,
|
||||
} from "../interfaces";
|
||||
|
||||
function writeQueue(from: From, tracks: Track[]) {
|
||||
localStorage.setItem(
|
||||
"queue",
|
||||
JSON.stringify({
|
||||
from: from,
|
||||
tracks: tracks,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function writeCurrent(index: number) {
|
||||
localStorage.setItem("current", JSON.stringify(index));
|
||||
}
|
||||
|
||||
function readCurrent(): number {
|
||||
const current = localStorage.getItem("current");
|
||||
|
||||
if (current) {
|
||||
return JSON.parse(current);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function shuffle(tracks: Track[]) {
|
||||
const shuffled = tracks.slice();
|
||||
for (let i = shuffled.length - 1; i > 0; i--) {
|
||||
@ -48,19 +23,15 @@ function shuffle(tracks: Track[]) {
|
||||
|
||||
type From = fromFolder | fromAlbum | fromPlaylist | fromSearch;
|
||||
|
||||
let audio = new Audio();
|
||||
|
||||
export default defineStore("Queue", {
|
||||
state: () => ({
|
||||
progressElem: HTMLElement,
|
||||
audio: new Audio(),
|
||||
duration: {
|
||||
current: 0,
|
||||
full: 0,
|
||||
},
|
||||
indexes: {
|
||||
current: 0,
|
||||
next: 0,
|
||||
previous: 0,
|
||||
},
|
||||
current: 0,
|
||||
next: 0,
|
||||
prev: 0,
|
||||
@ -81,25 +52,24 @@ export default defineStore("Queue", {
|
||||
this.updateCurrent(index);
|
||||
|
||||
new Promise((resolve, reject) => {
|
||||
this.audio.autoplay = true;
|
||||
this.audio.src = uri;
|
||||
this.audio.oncanplaythrough = resolve;
|
||||
this.audio.onerror = reject;
|
||||
audio.autoplay = true;
|
||||
audio.src = uri;
|
||||
audio.oncanplaythrough = resolve;
|
||||
audio.onerror = reject;
|
||||
})
|
||||
.then(() => {
|
||||
this.duration.full = this.audio.duration;
|
||||
this.audio.play().then(() => {
|
||||
this.duration.full = audio.duration;
|
||||
audio.play().then(() => {
|
||||
this.playing = true;
|
||||
notif(track, this.playPause, this.playNext, this.playPrev);
|
||||
|
||||
this.audio.ontimeupdate = () => {
|
||||
this.duration.current = this.audio.currentTime;
|
||||
const bg_size =
|
||||
(this.audio.currentTime / this.audio.duration) * 100;
|
||||
audio.ontimeupdate = () => {
|
||||
this.duration.current = audio.currentTime;
|
||||
const bg_size = (audio.currentTime / audio.duration) * 100;
|
||||
elem.style.backgroundSize = `${bg_size}% 100%`;
|
||||
};
|
||||
|
||||
this.audio.onended = () => {
|
||||
audio.onended = () => {
|
||||
this.playNext();
|
||||
};
|
||||
});
|
||||
@ -119,13 +89,13 @@ export default defineStore("Queue", {
|
||||
});
|
||||
},
|
||||
playPause() {
|
||||
if (this.audio.src === "") {
|
||||
if (audio.src === "") {
|
||||
this.play(this.current);
|
||||
} else if (this.audio.paused) {
|
||||
this.audio.play();
|
||||
} else if (audio.paused) {
|
||||
audio.play();
|
||||
this.playing = true;
|
||||
} else {
|
||||
this.audio.pause();
|
||||
audio.pause();
|
||||
this.playing = false;
|
||||
}
|
||||
},
|
||||
@ -137,7 +107,7 @@ export default defineStore("Queue", {
|
||||
},
|
||||
seek(pos: number) {
|
||||
try {
|
||||
this.audio.currentTime = pos;
|
||||
audio.currentTime = pos;
|
||||
} catch (error) {
|
||||
if (error instanceof TypeError) {
|
||||
console.error("Seek error: no audio");
|
||||
@ -152,15 +122,11 @@ export default defineStore("Queue", {
|
||||
this.from = parsed.from;
|
||||
this.tracklist = parsed.tracks;
|
||||
}
|
||||
|
||||
this.updateCurrent(readCurrent());
|
||||
},
|
||||
updateCurrent(index: number) {
|
||||
this.setCurrent(index);
|
||||
this.updateNext(index);
|
||||
this.updatePrev(index);
|
||||
|
||||
writeCurrent(index);
|
||||
},
|
||||
updateNext(index: number) {
|
||||
if (index == this.tracklist.length - 1) {
|
||||
@ -190,7 +156,6 @@ export default defineStore("Queue", {
|
||||
if (this.tracklist !== tracklist) {
|
||||
this.tracklist = [];
|
||||
this.tracklist.push(...tracklist);
|
||||
writeQueue(this.from, this.tracklist);
|
||||
}
|
||||
},
|
||||
playFromFolder(fpath: string, tracks: Track[]) {
|
||||
@ -235,7 +200,7 @@ export default defineStore("Queue", {
|
||||
},
|
||||
addTrackToQueue(track: Track) {
|
||||
this.tracklist.push(track);
|
||||
writeQueue(this.from, this.tracklist);
|
||||
// writeQueue(this.from, this.tracklist);
|
||||
this.updateNext(this.current);
|
||||
},
|
||||
playTrackNext(track: Track) {
|
||||
@ -264,16 +229,12 @@ export default defineStore("Queue", {
|
||||
`Added ${track.title} to queue`,
|
||||
NotifType.Success
|
||||
);
|
||||
writeQueue(this.from, this.tracklist);
|
||||
},
|
||||
clearQueue() {
|
||||
this.tracklist = [] as Track[];
|
||||
this.currentid = "";
|
||||
this.current, this.next, (this.prev = 0);
|
||||
this.from = <From>{};
|
||||
|
||||
writeCurrent(0);
|
||||
writeQueue(this.from, [] as Track[]);
|
||||
},
|
||||
shuffleQueue() {
|
||||
const Toast = useNotifStore();
|
||||
@ -291,12 +252,38 @@ export default defineStore("Queue", {
|
||||
this.currentid = shuffled[0].trackid;
|
||||
this.next = 1;
|
||||
this.prev = this.tracklist.length - 1;
|
||||
|
||||
writeQueue(this.from, shuffled);
|
||||
writeCurrent(0);
|
||||
},
|
||||
removeFromQueue(index: number = 0) {
|
||||
this.tracklist.splice(index, 1);
|
||||
},
|
||||
},
|
||||
getters: {
|
||||
getNextTrack() {
|
||||
if (this.current == this.tracklist.length - 1) {
|
||||
return this.tracklist[0];
|
||||
} else {
|
||||
return this.tracklist[this.current + 1];
|
||||
}
|
||||
},
|
||||
getPrevTrack() {
|
||||
if (this.current === 0) {
|
||||
return this.tracklist[this.tracklist.length - 1];
|
||||
} else {
|
||||
return this.tracklist[this.current - 1];
|
||||
}
|
||||
},
|
||||
fullTime() {
|
||||
return audio.duration;
|
||||
},
|
||||
currentTime() {
|
||||
return audio.currentTime;
|
||||
},
|
||||
getCurrentTrack() {
|
||||
return this.tracklist[this.current];
|
||||
},
|
||||
getIsplaying() {
|
||||
return audio.paused ? false : true;
|
||||
},
|
||||
},
|
||||
persist: true,
|
||||
});
|
||||
|
@ -106,7 +106,8 @@ onBeforeRouteUpdate((to, from) => {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
object-fit: cover;
|
||||
object-position: bottom;
|
||||
object-position: bottom right;
|
||||
transition: all .25s ease;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,8 +14,8 @@
|
||||
<script setup lang="ts">
|
||||
import PlaylistCard from "@/components/playlists/PlaylistCard.vue";
|
||||
|
||||
import usePStore from "@/stores/pages/playlists";
|
||||
import NewPlaylistCard from "@/components/playlists/NewPlaylistCard.vue";
|
||||
import usePStore from "@/stores/pages/playlists";
|
||||
const pStore = usePStore();
|
||||
</script>
|
||||
|
||||
|
7
src/vite-env.d.ts
vendored
Normal file
7
src/vite-env.d.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
declare module '*.vue' {
|
||||
import type { DefineComponent } from 'vue'
|
||||
const component: DefineComponent<{}, {}, any>
|
||||
export default component
|
||||
}
|
@ -1,11 +1,40 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"target": "ESNext",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
// "strict": true,
|
||||
"jsx": "preserve",
|
||||
"sourceMap": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"esModuleInterop": true,
|
||||
"lib": ["ESNext", "DOM"],
|
||||
"skipLibCheck": true,
|
||||
"paths": {
|
||||
"baseUrl": ["./"],
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src/**/*"]
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.d.ts",
|
||||
"src/**/*.tsx",
|
||||
"src/**/*.vue",
|
||||
"src/**/*.svg"
|
||||
],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
|
||||
// {
|
||||
// "compilerOptions": {
|
||||
// "strict": false,
|
||||
// "jsx": "preserve",
|
||||
// "paths": {
|
||||
// "baseUrl": ["./"],
|
||||
// "@/*": ["./src/*"]
|
||||
// }
|
||||
// },
|
||||
// "include": ["src/**/*"]
|
||||
// }
|
||||
|
9
tsconfig.node.json
Normal file
9
tsconfig.node.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import vue from "@vitejs/plugin-vue";
|
||||
import { defineConfig } from "vite";
|
||||
import vue from "@vitejs/plugin-vue";
|
||||
import svgLoader from "vite-svg-loader";
|
||||
|
||||
const path = require("path");
|
Loading…
x
Reference in New Issue
Block a user