first commit
This commit is contained in:
184
resources/js/Layouts/AppLayout.vue
Normal file
184
resources/js/Layouts/AppLayout.vue
Normal file
@@ -0,0 +1,184 @@
|
||||
<template>
|
||||
<div class="flex h-screen">
|
||||
<!-- Sidebar -->
|
||||
<aside class="w-64 flex flex-col h-full border-r" style="border-color: var(--p-dialog-border-color)">
|
||||
<!-- Logo -->
|
||||
<div class="p-2 border-b" style="border-color: var(--p-dialog-border-color)">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-10 h-10 bg-gradient-to-br from-primary-500 to-primary-600 rounded-xl flex items-center justify-center shadow-lg">
|
||||
<i class="pi pi-database text-xl text-white"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h1 class="text-lg font-bold text-white">Репликация БД</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- PanelMenu -->
|
||||
<PanelMenu
|
||||
:model="menuItems"
|
||||
v-model:expanded-keys="expandedKeys"
|
||||
class="w-full border-none bg-transparent flex-1 overflow-y-auto">
|
||||
<template #item="{item, active, hasSubmenu}">
|
||||
<Link v-if="item.url" class="flex items-center cursor-pointer px-4 py-2" :href="item.url">
|
||||
<span :class="item.icon" style="font-size: 14px;" />
|
||||
<span class="ml-2 text-sm">{{ item.label }}</span>
|
||||
<span v-if="hasSubmenu" class="pi pi-angle-down ml-auto" style="font-size: 14px;" />
|
||||
</Link>
|
||||
<div v-else class="text-sm flex items-center cursor-pointer px-4 py-2">
|
||||
<span :class="item.icon" style="font-size: 14px;" />
|
||||
<span :class="{'ml-2': item.icon}">{{ item.label }}</span>
|
||||
<span v-if="hasSubmenu" class="pi pi-angle-down ml-auto" style="font-size: 14px;" />
|
||||
</div>
|
||||
</template>
|
||||
</PanelMenu>
|
||||
|
||||
<!-- User Section -->
|
||||
<div class="p-4 border-t" style="border-color: var(--p-dialog-border-color)">
|
||||
<div class="flex items-center gap-3 p-2 rounded-lg">
|
||||
<Avatar label="A" shape="circle" size="normal" />
|
||||
<div class="flex-1">
|
||||
<p class="text-sm font-medium">Администратор</p>
|
||||
<p class="text-xs">admin@db.local</p>
|
||||
</div>
|
||||
<Button icon="pi pi-sign-out" text rounded severity="secondary" size="small" />
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- Main Content -->
|
||||
<main class="flex-1 overflow-y-auto">
|
||||
<!-- Top Toolbar -->
|
||||
<Toolbar class="border-t-0! border-l-0! border-r-0! border-b! rounded-none! px-6!" style="border-color: var(--p-dialog-border-color)">
|
||||
<template #start>
|
||||
<slot name="header" />
|
||||
</template>
|
||||
<template #end>
|
||||
<div class="flex items-center gap-2">
|
||||
<Button
|
||||
:icon="isDark ? 'pi pi-sun' : 'pi pi-moon'"
|
||||
@click="toggleTheme"
|
||||
severity="secondary"
|
||||
text
|
||||
rounded
|
||||
size="small"
|
||||
/>
|
||||
<Button icon="pi pi-bell" severity="secondary" text rounded size="small" />
|
||||
</div>
|
||||
</template>
|
||||
</Toolbar>
|
||||
|
||||
<!-- Page Content -->
|
||||
<div class="p-6">
|
||||
<slot />
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { inject, ref } from 'vue';
|
||||
import { usePage, Link } from '@inertiajs/vue3';
|
||||
import PanelMenu from 'primevue/panelmenu';
|
||||
import Toolbar from 'primevue/toolbar';
|
||||
import Button from 'primevue/button';
|
||||
import Avatar from 'primevue/avatar';
|
||||
|
||||
const page = usePage();
|
||||
const { isDark, toggle } = inject('theme');
|
||||
|
||||
const expandedKeys = ref({'0': true});
|
||||
|
||||
const menuItems = [
|
||||
{
|
||||
key: '0',
|
||||
label: 'Панель управления',
|
||||
items: [
|
||||
{
|
||||
key: '0_1',
|
||||
label: 'Главная',
|
||||
icon: 'pi pi-home',
|
||||
url: '/',
|
||||
},
|
||||
{
|
||||
key: '0_2',
|
||||
label: 'Базы данных',
|
||||
icon: 'pi pi-database',
|
||||
items: [
|
||||
{
|
||||
key: '0_2_1',
|
||||
label: 'Исходные БД',
|
||||
icon: 'pi pi-server',
|
||||
url: '/databases/source',
|
||||
},
|
||||
{
|
||||
key: '0_2_2',
|
||||
label: 'Целевые БД',
|
||||
icon: 'pi pi-cloud-download',
|
||||
url: '/databases/target',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: '0_3',
|
||||
label: 'Схемы',
|
||||
icon: 'pi pi-table',
|
||||
url: '/schemas',
|
||||
},
|
||||
{
|
||||
key: '0_4',
|
||||
label: 'Расписания миграций',
|
||||
icon: 'pi pi-calendar',
|
||||
url: '/migrations',
|
||||
},
|
||||
]
|
||||
},
|
||||
];
|
||||
|
||||
// Определяем активный пункт меню
|
||||
const getActiveItem = () => {
|
||||
const url = page.url;
|
||||
if (url === '/') return 'Главная';
|
||||
if (url.startsWith('/databases/source')) return 'Исходные БД';
|
||||
if (url.startsWith('/databases/target')) return 'Целевые БД';
|
||||
if (url.startsWith('/schemas')) return 'Схемы';
|
||||
if (url.startsWith('/migrations')) return 'Расписания миграций';
|
||||
return null;
|
||||
};
|
||||
|
||||
const toggleTheme = () => {
|
||||
toggle();
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* Кастомизация PanelMenu */
|
||||
:deep(.p-panelmenu) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
:deep(.p-panelmenu-panel) {
|
||||
border: none;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
:deep(.p-panelmenu-root-list) {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
:deep(.p-panelmenu-item-link) {
|
||||
padding: 0.625rem 0.75rem !important;
|
||||
}
|
||||
|
||||
:deep(.p-panelmenu-item-icon) {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
:deep(.p-panelmenu-item.p-highlight) {
|
||||
background-color: rgba(99, 102, 241, 0.1) !important;
|
||||
}
|
||||
|
||||
:deep(.p-panelmenu-item.p-highlight .p-panelmenu-item-label) {
|
||||
color: rgb(99, 102, 241) !important;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user