refactor UI layout

This commit is contained in:
geoffrey45
2022-03-06 10:27:01 +03:00
parent 90f8703a8e
commit 7f2102f931
21 changed files with 214 additions and 164 deletions
+1
View File
@@ -11,6 +11,7 @@
"dependencies": { "dependencies": {
"axios": "^0.26.0", "axios": "^0.26.0",
"mitt": "^3.0.0", "mitt": "^3.0.0",
"pinia": "^2.0.11",
"register-service-worker": "^1.7.1", "register-service-worker": "^1.7.1",
"sass": "^1.49.0", "sass": "^1.49.0",
"sass-loader": "^10", "sass-loader": "^10",
+2 -1
View File
@@ -11,7 +11,8 @@ bp = Blueprint("api", __name__, url_prefix="")
home_dir = helpers.home_dir home_dir = helpers.home_dir
all_the_f_music = helpers.get_all_songs() all_the_f_albums = helpers.create_all_albums()
all_the_f_music = helpers.create_all_tracks()
def initialize() -> None: def initialize() -> None:
+5 -10
View File
@@ -20,6 +20,7 @@ from app import helpers
from app import instances from app import instances
from app import api from app import api
from app import models from app import models
import urllib
def populate(): def populate():
@@ -41,7 +42,7 @@ def populate():
if tags is not None: if tags is not None:
instances.songs_instance.insert_song(tags) instances.songs_instance.insert_song(tags)
api.all_the_f_music = helpers.get_all_songs() api.all_the_f_music = helpers.create_all_tracks()
print("\n check done") print("\n check done")
end = time.time() end = time.time()
@@ -165,7 +166,7 @@ def extract_thumb(audio_file_path: str) -> str:
""" """
Extracts the thumbnail from an audio file. Returns the path to the thumbnail. Extracts the thumbnail from an audio file. Returns the path to the thumbnail.
""" """
webp_path = audio_file_path.split("/")[-1] + ".webp" webp_path = urllib.parse.quote_plus(audio_file_path.split("/")[-1] + ".webp")
img_path = os.path.join(helpers.app_dir, "images", "thumbnails", webp_path) img_path = os.path.join(helpers.app_dir, "images", "thumbnails", webp_path)
if os.path.exists(img_path): if os.path.exists(img_path):
@@ -366,16 +367,10 @@ def get_all_albums():
album["count"] = len(album_tracks) album["count"] = len(album_tracks)
album["duration"] = helpers.get_album_duration(album_tracks) album["duration"] = helpers.get_album_duration(album_tracks)
album["date"] = album_tracks[0]["date"] album["date"] = album_tracks[0]["date"]
album["artistimage"] = ( album["artistimage"] = urllib.parse.quote_plus(
"http://127.0.0.1:8900/images/artists/" album_tracks[0]["albumartist"] + ".webp"
+ album_tracks[0]["albumartist"].replace("/", "::")
+ ".webp"
) )
if len(album_tracks) == 1:
album["image"] = extract_thumb(album_tracks[0]["filepath"])
if len(album_tracks) > 1:
album["image"] = helpers.get_album_image(album_tracks) album["image"] = helpers.get_album_image(album_tracks)
instances.album_instance.insert_album(album) instances.album_instance.insert_album(album)
+16 -1
View File
@@ -146,7 +146,7 @@ def create_config_dir() -> None:
os.chmod(path, 0o755) os.chmod(path, 0o755)
def get_all_songs() -> List[models.Track]: def create_all_tracks() -> List[models.Track]:
""" """
Gets all songs under the ~/ directory. Gets all songs under the ~/ directory.
""" """
@@ -160,11 +160,26 @@ def get_all_songs() -> List[models.Track]:
except FileNotFoundError: except FileNotFoundError:
instances.songs_instance.remove_song_by_filepath(track["filepath"]) instances.songs_instance.remove_song_by_filepath(track["filepath"])
album = instances.album_instance.get_album_by_name(track['album', track['albumartist']])
if album is None:
track['albumid'] = album['albumid']
track['image'] = album['image']
tracks.append(models.Track(track)) tracks.append(models.Track(track))
return tracks return tracks
def create_all_albums() -> List[models.Album]:
"""Creates album objects for all albums"""
albums: list[models.Album] = []
for album in instances.album_instance.get_all_albums():
albums.append(models.Album(album))
return albums
def extract_colors(image) -> list: def extract_colors(image) -> list:
"""Extracts 2 of the most dominant colors from an image.""" """Extracts 2 of the most dominant colors from an image."""
try: try:
+19 -10
View File
@@ -237,6 +237,7 @@ class Track:
""" """
trackid: str trackid: str
albumid: str
title: str title: str
artists: str artists: str
albumartist: str albumartist: str
@@ -244,7 +245,6 @@ class Track:
folder: str folder: str
filepath: str filepath: str
length: int length: int
date: int
genre: str genre: str
bitrate: int bitrate: int
image: str image: str
@@ -260,7 +260,6 @@ class Track:
self.folder = tags["folder"] self.folder = tags["folder"]
self.filepath = tags["filepath"] self.filepath = tags["filepath"]
self.length = tags["length"] self.length = tags["length"]
self.date = tags["date"]
self.genre = tags["genre"] self.genre = tags["genre"]
self.bitrate = tags["bitrate"] self.bitrate = tags["bitrate"]
self.image = "http://127.0.0.1:8900/images/thumbnails/" + tags["image"] self.image = "http://127.0.0.1:8900/images/thumbnails/" + tags["image"]
@@ -287,6 +286,13 @@ class Albums(Mongo):
upsert=True, upsert=True,
).upserted_id ).upserted_id
def get_all_albums(self) -> list:
"""
Returns all the albums in the database.
"""
albums = self.collection.find()
return convert_many(albums)
def get_album_by_id(self, id: str) -> dict: def get_album_by_id(self, id: str) -> dict:
""" """
Returns a single album matching the id in the query params. Returns a single album matching the id in the query params.
@@ -294,11 +300,11 @@ class Albums(Mongo):
album = self.collection.find_one({"_id": ObjectId(id)}) album = self.collection.find_one({"_id": ObjectId(id)})
return convert_one(album) return convert_one(album)
def get_album_by_name(self, name: str) -> dict: def get_album_by_name(self, name: str, artist: str) -> dict:
""" """
Returns a single album matching the name in the query params. Returns a single album matching the name in the query params.
""" """
album = self.collection.find_one({"album": name}) album = self.collection.find_one({"album": name, "artist": artist})
return convert_one(album) return convert_one(album)
def get_album_by_artist(self, name: str) -> dict: def get_album_by_artist(self, name: str) -> dict:
@@ -318,15 +324,18 @@ class Album:
albumid: str albumid: str
album: str album: str
artist: str artist: str
albumartist: str count: int
year: int duration: int
date: int
artistimage: str
image: str image: str
tracks: list
def __init__(self, tags): def __init__(self, tags):
self.albumid = tags["_id"]["$oid"] self.albumid = tags["_id"]["$oid"]
self.album = tags["album"] self.album = tags["album"]
self.artist = tags["artist"] self.artist = tags["artist"]
self.albumartist = tags["albumartist"] self.count = tags["count"]
self.year = tags["year"] self.duration = tags["duration"]
self.image = "" self.date = tags["date"]
self.artistimage = tags["artistimage"]
self.image = tags["image"]
+10 -32
View File
@@ -3,7 +3,6 @@
<div class="l-container" :class="{ collapsed: collapsed }"> <div class="l-container" :class="{ collapsed: collapsed }">
<div class="l-sidebar"> <div class="l-sidebar">
<div id="logo-container"> <div id="logo-container">
<!-- <div id="toggle" @click="toggleNav"></div> -->
<router-link :to="{ name: 'Home' }" v-if="!collapsed" <router-link :to="{ name: 'Home' }" v-if="!collapsed"
><div class="logo"></div ><div class="logo"></div
></router-link> ></router-link>
@@ -18,49 +17,28 @@
<router-view /> <router-view />
</div> </div>
<RightSideBar /> <RightSideBar />
<Tabs />
<div class="bottom-bar"> <div class="bottom-bar">
<BottomBar :collapsed="collapsed"/> <BottomBar :collapsed="collapsed" />
</div> </div>
</div> </div>
</template> </template>
<script> <script setup>
import { ref } from "@vue/reactivity"; import { ref } from "vue";
import Navigation from "./components/LeftSidebar/Navigation.vue"; import Navigation from "./components/LeftSidebar/Navigation.vue";
import PinnedStuff from "./components/LeftSidebar/PinnedStuff.vue";
import BottomBar from "@/components/BottomBar/BottomBar.vue"; import BottomBar from "@/components/BottomBar/BottomBar.vue";
import perks from "@/composables/perks.js"; import perks from "@/composables/perks.js";
import Main from "./components/RightSideBar/Main.vue"; import Main from "./components/RightSideBar/Main.vue";
import AlbumArt from "./components/LeftSidebar/AlbumArt.vue"; import AlbumArt from "./components/LeftSidebar/AlbumArt.vue";
import NavBar from "./components/nav/NavBar.vue"; import NavBar from "./components/nav/NavBar.vue";
import Tabs from "./components/RightSideBar/Tabs.vue";
export default { const RightSideBar = Main;
components: { perks.readQueue();
Navigation, const collapsed = ref(false);
PinnedStuff,
BottomBar,
RightSideBar: Main,
AlbumArt,
NavBar
},
setup() {
const collapsed = ref(false);
perks.readQueue();
function toggleNav() {
collapsed.value = !collapsed.value;
}
return {
toggleNav,
collapsed,
};
},
};
</script> </script>
<style lang="scss"> <style lang="scss">
@@ -93,7 +71,7 @@ export default {
height: 4.5rem; height: 4.5rem;
width: 15rem; width: 15rem;
background: url(./assets/icons/logo.svg) no-repeat 1rem; background: url(./assets/icons/logo.svg) no-repeat 1rem;
background-size:9rem; background-size: 9rem;
} }
.r-sidebar { .r-sidebar {
+3 -3
View File
@@ -1,11 +1,12 @@
.b-bar { .b-bar {
height: 100%; height: 100%;
background-color: $gray; padding: $small;
.grid { .grid {
background-color: $gray;
display: grid; display: grid;
height: 100%; height: 100%;
grid-template-columns: 1fr 2fr 1fr; padding-right: $small;
@include phone-only { @include phone-only {
grid-template-columns: 1fr 9.2rem; grid-template-columns: 1fr 9.2rem;
@@ -45,7 +46,6 @@
overflow: hidden; overflow: hidden;
display: flex; display: flex;
align-items: center; align-items: center;
margin: $small;
padding: $small; padding: $small;
.progress-bottom { .progress-bottom {
+1 -1
View File
@@ -26,7 +26,7 @@ $gray5: rgb(44, 44, 46);
$red: rgb(255, 69, 58); $red: rgb(255, 69, 58);
$blue: rgb(10, 132, 255); $blue: rgb(10, 132, 255);
$green: rgb(48, 209, 88); $green: rgb(20, 160, 55);
$yellow: rgb(255, 214, 10); $yellow: rgb(255, 214, 10);
$orange: rgb(255, 159, 10); $orange: rgb(255, 159, 10);
$pink: rgb(255, 55, 95); $pink: rgb(255, 55, 95);
+8 -3
View File
@@ -87,14 +87,18 @@ button {
grid-template-rows: 3rem 1fr 1fr; grid-template-rows: 3rem 1fr 1fr;
grid-auto-flow: row; grid-auto-flow: row;
grid-template-areas: grid-template-areas:
"l-sidebar nav nav" "l-sidebar nav r-sidebar"
"l-sidebar content r-sidebar" "l-sidebar content r-sidebar"
"l-sidebar content r-sidebar" "l-sidebar content r-sidebar"
"bottom-bar bottom-bar bottom-bar"; "l-sidebar bottom-bar tabs";
width: 100vw; width: 100vw;
height: 100vh; height: 100vh;
} }
.tabs {
grid-area: tabs;
}
.topnav { .topnav {
grid-area: nav; grid-area: nav;
} }
@@ -103,6 +107,7 @@ button {
width: 15rem; width: 15rem;
grid-area: l-sidebar; grid-area: l-sidebar;
padding-top: 0.5rem; padding-top: 0.5rem;
border-right: solid 1px $gray;
} }
.bottom-bar { .bottom-bar {
@@ -139,7 +144,7 @@ button {
grid-area: content; grid-area: content;
overflow: hidden; overflow: hidden;
padding: 0; padding: 0;
border-left: solid 1px $gray; max-width: 1504px;
.nav { .nav {
border: solid; border: solid;
+8 -10
View File
@@ -1,6 +1,6 @@
<template> <template>
<div class="album-h"> <div class="album-h">
<div class="a-header rounded"> <div class="a-header">
<div <div
class="image art shadow-lg" class="image art shadow-lg"
:style="{ backgroundImage: `url(&quot;${encodeURI(props.album_info.image)}&quot;)` }" :style="{ backgroundImage: `url(&quot;${encodeURI(props.album_info.image)}&quot;)` }"
@@ -64,16 +64,14 @@ function playAlbum() {
padding: 1rem; padding: 1rem;
height: 100%; height: 100%;
background-image: linear-gradient( background-image: linear-gradient(
56deg, to bottom,
$gray 0%, $gray3 0%,
$gray4 25%, $gray3 25%,
$gray1 50%, $gray3 35%,
$gray1 75%, $gray4 50%,
$gray 100% $gray 75%,
$black 100%
); );
background-position: 0% 60%;
background-repeat: no-repeat;
background-size: cover;
.art { .art {
position: absolute; position: absolute;
+2 -10
View File
@@ -1,7 +1,6 @@
<template> <template>
<div class="b-bar"> <div class="b-bar ">
<div class="grid"> <div class="grid rounded">
<SongCard :collapsed="props.collapsed" />
<div class="controlsx rounded"> <div class="controlsx rounded">
<div class="controls controls-bottom"> <div class="controls controls-bottom">
<HotKeys /> <HotKeys />
@@ -27,7 +26,6 @@
<script setup> <script setup>
import "../../assets/css/BottomBar/BottomBar.scss"; import "../../assets/css/BottomBar/BottomBar.scss";
import SongCard from "./SongCard.vue";
import Progress from "../shared/Progress.vue"; import Progress from "../shared/Progress.vue";
import HotKeys from "../shared/HotKeys.vue"; import HotKeys from "../shared/HotKeys.vue";
import state from "../../composables/state"; import state from "../../composables/state";
@@ -37,10 +35,4 @@ import playAudio from "../../composables/playAudio";
const current_pos = playAudio.current_time const current_pos = playAudio.current_time
const formatSeconds = perks.formatSeconds; const formatSeconds = perks.formatSeconds;
const props = defineProps({
collapsed: {
type: Boolean,
default: false,
},
});
</script> </script>
+9 -4
View File
@@ -1,17 +1,20 @@
<template> <template>
<div class="l_" v-if="!props.collapsed"> <div class="l_ rounded" v-if="!props.collapsed">
<div <div
class="l-image image" class="l-image image rounded"
:style="{ :style="{
backgroundImage: `url(&quot;${current.image}&quot;)`, backgroundImage: `url(&quot;${current.image}&quot;)`,
}" }"
></div> ></div>
<div class="separator no-border"></div>
<SongCard />
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref } from "vue"; import { ref } from "vue";
import state from "../../composables/state"; import state from "../../composables/state";
import SongCard from "./SongCard.vue";
const current = ref(state.current); const current = ref(state.current);
const props = defineProps({ const props = defineProps({
@@ -24,10 +27,12 @@ const props = defineProps({
<style lang="scss"> <style lang="scss">
.l_ { .l_ {
padding: $small; padding: $small;
background-color: #e24a01;
margin: $small;
.l-image { .l-image {
height: 14rem; height: 13rem;
width: 14rem; width: 13rem;
} }
} }
</style> </style>
+13 -38
View File
@@ -2,70 +2,45 @@
<div class="r-sidebar"> <div class="r-sidebar">
<div class="grid"> <div class="grid">
<div class="r-content"> <div class="r-content">
<div class="r-dash" v-show="current_tab === tabs.home"> <div class="r-dash" v-show="tabs.current === tabs.tabs.home">
<DashBoard /> <DashBoard />
</div> </div>
<div class="r-search" v-show="current_tab === tabs.search"> <div class="r-search" v-show="tabs.current === tabs.tabs.search">
<Search /> <Search />
</div> </div>
<div class="r-queue" v-show="current_tab === tabs.queue"> <div class="r-queue" v-show="tabs.current === tabs.tabs.queue">
<UpNext /> <UpNext />
</div> </div>
</div> </div>
<div class="tab-keys">
<Tabs :current_tab="current_tab" :tabs="tabs" @changeTab="changeTab" />
</div>
</div> </div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref } from "vue";
import Search from "./Search.vue"; import Search from "./Search.vue";
import UpNext from "./Queue.vue"; import UpNext from "./Queue.vue";
import Tabs from "./Tabs.vue";
import Main from "./Home/Main.vue"; import Main from "./Home/Main.vue";
import perks from "../../composables/perks"; import useTabStore from "../../stores/tabs";
const DashBoard = Main; const DashBoard = Main;
const tabs = useTabStore();
const tabs = {
home: "home",
search: "search",
queue: "queue",
};
const default_tab = tabs.home;
const current_tab = ref(default_tab);
function changeTab(tab) {
new Promise((resolve) => {
current_tab.value = tab;
resolve();
setTimeout(() => {}, 300);
}).then(() => {
if (tab === tabs.queue) {
setTimeout(() => {
perks.focusCurrent();
}, 300);
}
});
}
</script> </script>
<style lang="scss"> <style lang="scss">
.r-sidebar { .r-sidebar {
width: 32em; width: 29em;
background-color: rgba(4, 12, 34, 0.103);
padding: 0 0 0 $small;
border-left: 1px solid $gray;
@include phone-only { @include phone-only {
display: none; display: none;
} }
// @include tablet-landscape { @include tablet-landscape {
// width: 3rem; display: none;
// } }
.grid { .grid {
height: 100%; height: 100%;
@@ -76,7 +51,6 @@ function changeTab(tab) {
grid-area: content; grid-area: content;
width: 29rem; width: 29rem;
// @include tablet-landscape { // @include tablet-landscape {
// display: none; // display: none;
// } // }
@@ -95,6 +69,7 @@ function changeTab(tab) {
} }
.tab-keys { .tab-keys {
display: none;
width: 3rem; width: 3rem;
right: 0; right: 0;
height: 100%; height: 100%;
+23 -29
View File
@@ -1,47 +1,44 @@
<template> <template>
<div class="r-tabs"> <div class="tabs">
<div v-for="tab in props.tabs" <div class="cont rounded">
@click="changeTab(tab)" <div
v-for="tab in tabs.tabs"
@click="tabs.changeTab(tab)"
:key="tab" :key="tab"
class="image t-item" class="image t-item"
:class="{ active_tab: props.current_tab === tab }, `${tab}`" :class="({ active_tab: tabs.current === tab }, `${tab}`)"
></div> ></div>
<div>
</div> </div>
</div> </div>
</template> </template>
<script setup> <script setup>
import useTabStore from "../../stores/tabs";
const props = defineProps({ const tabs = useTabStore()
current_tab: String,
tabs: Object,
});
const emit = defineEmits(['changeTab'])
function changeTab(tab) {
if (tab === props.current_tab) return;
emit('changeTab', tab)
}
</script> </script>
<style lang="scss"> <style lang="scss">
.r-tabs { .tabs {
padding: $small;
border-left: 1px solid $gray;
.cont {
background-color: $gray;
display: flex; display: flex;
flex-direction: column;
gap: $small; gap: $small;
margin-top: $small; height: 100%;
margin-left: $small; align-items: center;
padding-left: $small;
}
.t-item { .t-item {
float: right; float: right;
width: 100%; width: 2.25rem;
height: 2.45rem; height: 2.25rem;
background-size: 1.5rem; background-size: 1.5rem;
border-radius: $small 0 0 $small; border-radius: $small;
background-color: $gray4;
&:hover { &:hover {
background-color: rgba(128, 128, 128, 0.281); background-color: rgba(128, 128, 128, 0.281);
@@ -49,23 +46,20 @@ function changeTab(tab) {
} }
.active_tab { .active_tab {
border-right: solid; border: solid;
background-color: rgba(17, 123, 223, 0.192); background-color: rgba(17, 123, 223, 0.192);
} }
.search { .search {
background-image: url("../../assets/icons/search.svg"); background-image: url("../../assets/icons/search.svg");
// background-color: rgba(35, 35, 66, 0.247);
} }
.queue { .queue {
background-image: url("../../assets/icons/queue.svg"); background-image: url("../../assets/icons/queue.svg");
// background-color: rgba(46, 25, 33, 0.445);
} }
.home { .home {
background-image: url("../../assets/icons/dashboard.svg"); background-image: url("../../assets/icons/dashboard.svg");
// background-color: rgba(148, 102, 50, 0.445);
} }
} }
</style> </style>
+31 -3
View File
@@ -1,14 +1,42 @@
<template> <template>
<div class="topnav"></div> <div class="topnav rounded">
<div class="left">
<div class="btn">
<PlayBtn />
</div>
<div class="info">
<div class="title">The Queen of Soul</div>
</div>
</div>
<div class="center"></div>
<div class="right"></div>
</div>
</template> </template>
<script setup> <script setup>
function toggleNav() {} import PlayBtn from '../shared/PlayBtn.vue';
</script> </script>
<style lang="scss"> <style lang="scss">
.topnav { .topnav {
background-color: $gray; background-color: $gray3;
display: grid; display: grid;
grid-template-columns: repeat(3, 1fr);
padding: 0 $small;
margin: $small $small 0 $small;
.left {
display: flex;
// border: solid 1px $gray;
align-items: center;
gap: $small;
.info {
.title {
font-size: 1.5rem;
font-weight: bold;
}
}
}
} }
</style> </style>
+23
View File
@@ -0,0 +1,23 @@
<template>
<div class="play-btn circular">
<div class="icon"></div>
</div>
</template>
<style lang="scss">
.play-btn {
width: 2rem;
height: 2rem;
background-color: $red;
background-image: url("../../assets/icons/play.svg");
background-size: 1.25rem;
background-position: 60%;
background-repeat: no-repeat;
transition: all .25s;
&:hover {
background-color: rgb(58, 197, 58);
transform: scale(1.1);
}
}
</style>
+1 -1
View File
@@ -207,7 +207,7 @@ export default {
.song-album { .song-album {
.album { .album {
cursor: pointer; cursor: pointer;
width: max-content; max-width: max-content;
} }
@include tablet-portrait { @include tablet-portrait {
+11 -1
View File
@@ -50,7 +50,15 @@ const is_playing = ref(false);
const settings = reactive({ const settings = reactive({
uri: "http://0.0.0.0:9876", uri: "http://0.0.0.0:9876",
}) });
const tablist = {
home: "home",
search: "search",
queue: "queue",
};
const current_tab = ref(tablist.home);
export default { export default {
search_query, search_query,
@@ -65,4 +73,6 @@ export default {
is_playing, is_playing,
album, album,
settings, settings,
current_tab,
tablist
}; };
+3
View File
@@ -2,9 +2,12 @@ import { createApp } from "vue";
import App from "./App.vue"; import App from "./App.vue";
import "./registerServiceWorker"; import "./registerServiceWorker";
import router from "./router"; import router from "./router";
import { createPinia } from 'pinia'
import "../src/assets/css/global.scss"; import "../src/assets/css/global.scss";
const app = createApp(App); const app = createApp(App);
app.use(router); app.use(router);
app.use(createPinia())
app.mount('#app'); app.mount('#app');
+18
View File
@@ -119,6 +119,11 @@
resolved "https://registry.yarnpkg.com/@vue/devtools-api/-/devtools-api-6.0.0-beta.21.1.tgz#f1410f53c42aa67fa3b01ca7bdba891f69d7bc97" resolved "https://registry.yarnpkg.com/@vue/devtools-api/-/devtools-api-6.0.0-beta.21.1.tgz#f1410f53c42aa67fa3b01ca7bdba891f69d7bc97"
integrity sha512-FqC4s3pm35qGVeXRGOjTsRzlkJjrBLriDS9YXbflHLsfA9FrcKzIyWnLXoNm+/7930E8rRakXuAc2QkC50swAw== integrity sha512-FqC4s3pm35qGVeXRGOjTsRzlkJjrBLriDS9YXbflHLsfA9FrcKzIyWnLXoNm+/7930E8rRakXuAc2QkC50swAw==
"@vue/devtools-api@^6.0.0-beta.21":
version "6.0.12"
resolved "https://registry.yarnpkg.com/@vue/devtools-api/-/devtools-api-6.0.12.tgz#7b57cce215ae9f37a86984633b3aa3d595aa5b46"
integrity sha512-iO/4FIezHKXhiDBdKySCvJVh8/mZPxHpiQrTy+PXVqJZgpTPTdHy4q8GXulaY+UKEagdkBb0onxNQZ0LNiqVhw==
"@vue/reactivity-transform@3.2.29": "@vue/reactivity-transform@3.2.29":
version "3.2.29" version "3.2.29"
resolved "https://registry.yarnpkg.com/@vue/reactivity-transform/-/reactivity-transform-3.2.29.tgz#a08d606e10016b7cf588d1a43dae4db2953f9354" resolved "https://registry.yarnpkg.com/@vue/reactivity-transform/-/reactivity-transform-3.2.29.tgz#a08d606e10016b7cf588d1a43dae4db2953f9354"
@@ -1175,6 +1180,14 @@ picomatch@^2.0.4, picomatch@^2.2.1:
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
pinia@^2.0.11:
version "2.0.11"
resolved "https://registry.yarnpkg.com/pinia/-/pinia-2.0.11.tgz#ff03c714f5e5f16207280a4fc2eab01f3701ee2b"
integrity sha512-JzcmnMqu28PNWOjDgEDK6fTrIzX8eQZKPPKvu/fpHdpXARUj1xeVdFi3YFIMOWswqaBd589cpmAMdSSTryI9iw==
dependencies:
"@vue/devtools-api" "^6.0.0-beta.21"
vue-demi "*"
postcss@^8.1.10, postcss@^8.4.5: postcss@^8.1.10, postcss@^8.4.5:
version "8.4.6" version "8.4.6"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.6.tgz#c5ff3c3c457a23864f32cb45ac9b741498a09ae1" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.6.tgz#c5ff3c3c457a23864f32cb45ac9b741498a09ae1"
@@ -1443,6 +1456,11 @@ vue-debounce@^3.0.2:
resolved "https://registry.yarnpkg.com/vue-debounce/-/vue-debounce-3.0.2.tgz#3b29c33db7cd2a8c20f77e0be66beda1b85f7e8d" resolved "https://registry.yarnpkg.com/vue-debounce/-/vue-debounce-3.0.2.tgz#3b29c33db7cd2a8c20f77e0be66beda1b85f7e8d"
integrity sha512-+shuc9Ry+AFqJbN7BMfagazB81/bTiPWvUZ4KBjambgrd3B5EQBojxeGzeNZ21xRflnwB098BG1d0HtWv8WyzA== integrity sha512-+shuc9Ry+AFqJbN7BMfagazB81/bTiPWvUZ4KBjambgrd3B5EQBojxeGzeNZ21xRflnwB098BG1d0HtWv8WyzA==
vue-demi@*:
version "0.12.1"
resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.12.1.tgz#f7e18efbecffd11ab069d1472d7a06e319b4174c"
integrity sha512-QL3ny+wX8c6Xm1/EZylbgzdoDolye+VpCXRhI2hug9dJTP3OUJ3lmiKN3CsVV3mOJKwFi0nsstbgob0vG7aoIw==
vue-eslint-parser@^8.0.1: vue-eslint-parser@^8.0.1:
version "8.2.0" version "8.2.0"
resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-8.2.0.tgz#8c3990deb901b0d528d99f4d052a831cd1d0284c" resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-8.2.0.tgz#8c3990deb901b0d528d99f4d052a831cd1d0284c"