Files
noctune-client/src/App.vue
T
2026-05-26 12:11:14 +07:00

71 lines
2.1 KiB
Vue

<template>
<div class="min-h-screen bg-noctune-cream">
<div v-if="!isAuthPage" class="flex flex-col min-h-screen">
<AppHeader />
<div class="flex flex-1">
<Sidebar />
<main class="flex-1 overflow-auto" :class="{ 'pb-20': hasPlayer }">
<router-view />
</main>
</div>
<PlayerBar />
</div>
<router-view v-else />
<div class="fixed top-4 right-4 z-[100] space-y-2">
<div v-for="toast in uiStore.toasts" :key="toast.id"
class="px-4 py-3 rounded-lg border-2 border-black font-bold text-sm shadow-[4px_4px_0px_0px_#000] transition-all animate-slide-in"
:class="toastClass(toast.type)"
>
<div class="flex items-center gap-2">
<span>{{ toast.message }}</span>
<button @click="uiStore.dismissToast(toast.id)" class="ml-2 opacity-60 hover:opacity-100">&times;</button>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { computed, onMounted } from 'vue'
import { useRoute } from 'vue-router'
import { useAuthStore } from './stores/authStore.js'
import { useUiStore } from './stores/uiStore.js'
import { usePlayerStore } from './stores/playerStore.js'
import AppHeader from './components/AppHeader.vue'
import Sidebar from './components/Sidebar.vue'
import PlayerBar from './components/PlayerBar.vue'
const route = useRoute()
const authStore = useAuthStore()
const uiStore = useUiStore()
const playerStore = usePlayerStore()
const isAuthPage = computed(() => {
return route.meta?.guest === true || route.path === '/register'
})
const hasPlayer = computed(() => !!playerStore.currentTrack)
function toastClass(type) {
return {
info: 'bg-noctune-teal text-black',
success: 'bg-green-400 text-black',
error: 'bg-red-400 text-white',
}[type] || 'bg-noctune-yellow text-black'
}
onMounted(async () => {
await authStore.checkSession()
})
</script>
<style>
.animate-slide-in {
animation: slideIn 0.3s ease-out;
}
@keyframes slideIn {
from { opacity: 0; transform: translateX(100%); }
to { opacity: 1; transform: translateX(0); }
}
</style>