Files
project-replica/resources/js/Layouts/AppLayout.vue
2026-03-23 00:51:38 +09:00

185 lines
6.3 KiB
Vue

<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>