feat: подготовил дизайн (изменения из другого репозитория)
🚀 Create and publish a Docker image / Detect changes in backend and frontend (push) Successful in 5s
🚀 Create and publish a Docker image / Build & publish backend image (push) Successful in 8s
🚀 Create and publish a Docker image / Update stack on Portainer (push) Successful in 3s
🚀 Create and publish a Docker image / Detect changes in backend and frontend (push) Successful in 5s
🚀 Create and publish a Docker image / Build & publish backend image (push) Successful in 8s
🚀 Create and publish a Docker image / Update stack on Portainer (push) Successful in 3s
This commit is contained in:
+92
-7
@@ -1,11 +1,96 @@
|
||||
<script setup lang="ts"></script>
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import AppTopbar from '@/components/layout/AppTopbar.vue'
|
||||
import AppSidebar from '@/components/layout/AppSidebar.vue'
|
||||
import AppBottomNav from '@/components/layout/AppBottomNav.vue'
|
||||
import ToastNotification from '@/components/ui/ToastNotification.vue'
|
||||
|
||||
const auth = useAuthStore()
|
||||
const route = useRoute()
|
||||
|
||||
const isAuthPage = computed(() => route.path === '/login')
|
||||
|
||||
interface Toast { id: number; message: string; type: 'success' | 'error' | 'info' }
|
||||
const toasts = ref<Toast[]>([])
|
||||
let toastId = 0
|
||||
|
||||
function addToast(msg: string, type: Toast['type'] = 'success') {
|
||||
toasts.value.push({ id: ++toastId, message: msg, type })
|
||||
}
|
||||
|
||||
function removeToast(id: number) {
|
||||
toasts.value = toasts.value.filter(t => t.id !== id)
|
||||
}
|
||||
|
||||
// expose globally via provide
|
||||
import { provide } from 'vue'
|
||||
provide('addToast', addToast)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h1>You did it!</h1>
|
||||
<p>
|
||||
Visit <a href="https://vuejs.org/" target="_blank" rel="noopener">vuejs.org</a> to read the
|
||||
documentation
|
||||
</p>
|
||||
<div class="app-root">
|
||||
<!-- Auth page: no layout -->
|
||||
<template v-if="isAuthPage">
|
||||
<RouterView />
|
||||
</template>
|
||||
|
||||
<!-- Main layout -->
|
||||
<template v-else-if="auth.isAuthenticated">
|
||||
<AppTopbar />
|
||||
<AppSidebar />
|
||||
<main class="main-content">
|
||||
<RouterView />
|
||||
</main>
|
||||
<AppBottomNav />
|
||||
</template>
|
||||
|
||||
<!-- Redirect to login if not authenticated -->
|
||||
<template v-else>
|
||||
<RouterView />
|
||||
</template>
|
||||
|
||||
<!-- Toast container -->
|
||||
<div class="toast-container">
|
||||
<ToastNotification
|
||||
v-for="t in toasts"
|
||||
:key="t.id"
|
||||
:message="t.message"
|
||||
:type="t.type"
|
||||
@close="removeToast(t.id)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped>
|
||||
.app-root {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.main-content {
|
||||
margin-top: var(--topbar-height);
|
||||
margin-left: var(--sidebar-width);
|
||||
min-height: calc(100vh - var(--topbar-height));
|
||||
padding: 28px 28px 80px;
|
||||
}
|
||||
.toast-container {
|
||||
position: fixed;
|
||||
bottom: 80px;
|
||||
right: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
z-index: 300;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.main-content {
|
||||
margin-left: 0;
|
||||
padding: 16px 16px 80px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user