443 lines
20 KiB
PHP
443 lines
20 KiB
PHP
<!DOCTYPE html>
|
|
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
|
|
|
<title>@yield('title', 'NetGesCon') - {{ config('app.name', 'Laravel') }}</title>
|
|
|
|
<!-- Fonts -->
|
|
<link rel="preconnect" href="https://fonts.bunny.net">
|
|
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet" />
|
|
|
|
<!-- Bootstrap CSS -->
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUa1y9lwNwQG0JI2V7B8JJwdq7YJ7ZJw3B8h9hXzpZ7E6F5v3Xp7a8rBQE4x" crossorigin="anonymous">
|
|
|
|
<!-- FontAwesome (per icone menu) -->
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" integrity="sha512-papm6Q6Q6Q6Q6Q6Q6Q6Q6Q6Q6Q6Q6Q6Q6Q6Q6Q6Q6Q6Q6Q6Q6Q6Q6Q6Q6Q6Q6Q6Q6Q6Q6Q6Q6Q6Q6Q6Q6Q==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
|
|
|
<!-- NetGesCon Universal Styles -->
|
|
<style>
|
|
:root {
|
|
--netgescon-primary: #2563eb;
|
|
--netgescon-secondary: #64748b;
|
|
--netgescon-success: #059669;
|
|
--netgescon-warning: #d97706;
|
|
--netgescon-danger: #dc2626;
|
|
--netgescon-info: #0284c7;
|
|
--netgescon-dark: #1f2937;
|
|
--netgescon-light: #f8fafc;
|
|
}
|
|
|
|
body {
|
|
font-family: 'Figtree', sans-serif;
|
|
background-color: var(--netgescon-light);
|
|
}
|
|
|
|
.main-content {
|
|
margin-left: 280px;
|
|
transition: margin-left 0.3s ease;
|
|
min-height: 100vh;
|
|
background-color: var(--netgescon-light);
|
|
padding: 20px;
|
|
}
|
|
|
|
.sidebar-responsive {
|
|
width: 280px;
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
height: 100vh;
|
|
z-index: 1000;
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.sidebar-responsive {
|
|
transform: translateX(-100%);
|
|
}
|
|
|
|
.main-content {
|
|
margin-left: 0;
|
|
padding: 15px;
|
|
}
|
|
|
|
.sidebar-responsive.show {
|
|
transform: translateX(0);
|
|
}
|
|
}
|
|
margin-left: 0;
|
|
}
|
|
|
|
.sidebar-responsive.show {
|
|
transform: translateX(0);
|
|
}
|
|
}
|
|
|
|
.sidebar-responsive {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
height: 100vh;
|
|
width: 280px;
|
|
z-index: 1000;
|
|
transition: transform 0.3s ease;
|
|
}
|
|
|
|
.top-navbar {
|
|
background: linear-gradient(135deg, var(--netgescon-primary) 0%, var(--netgescon-info) 100%);
|
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
z-index: 999;
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.main-content {
|
|
margin-left: 0;
|
|
}
|
|
}
|
|
|
|
.breadcrumb-netgescon {
|
|
background: white;
|
|
border-radius: 8px;
|
|
padding: 1rem;
|
|
margin-bottom: 1.5rem;
|
|
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
|
}
|
|
|
|
.card-netgescon {
|
|
border: none;
|
|
border-radius: 12px;
|
|
box-shadow: 0 4px 6px rgba(0,0,0,0.05);
|
|
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
|
}
|
|
|
|
.card-netgescon:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 8px 15px rgba(0,0,0,0.1);
|
|
}
|
|
|
|
.btn-netgescon-primary {
|
|
background: linear-gradient(135deg, var(--netgescon-primary) 0%, var(--netgescon-info) 100%);
|
|
border: none;
|
|
border-radius: 8px;
|
|
padding: 0.5rem 1.5rem;
|
|
color: white;
|
|
transition: all 0.2s ease;
|
|
}
|
|
|
|
.btn-netgescon-primary:hover {
|
|
transform: translateY(-1px);
|
|
box-shadow: 0 4px 12px rgba(37, 99, 235, 0.3);
|
|
color: white;
|
|
}
|
|
</style>
|
|
|
|
<!-- Scripts -->
|
|
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
|
|
|
@stack('styles')
|
|
</head>
|
|
<body>
|
|
{{-- Sidebar principale per desktop --}}
|
|
<div class="d-none d-md-block">
|
|
@include('components.menu.sidebar')
|
|
</div>
|
|
|
|
{{-- Contenuto principale --}}
|
|
<div class="main-content" id="main-content">
|
|
{{-- Top Navigation Bar --}}
|
|
<nav class="navbar top-navbar navbar-expand-lg navbar-dark">
|
|
<div class="container-fluid">
|
|
{{-- Mobile menu toggle --}}
|
|
<button class="btn btn-outline-light d-md-none me-2" id="mobile-menu-toggle">
|
|
<i class="fas fa-bars"></i>
|
|
</button>
|
|
|
|
{{-- Breadcrumb --}}
|
|
<div class="navbar-nav me-auto">
|
|
@hasSection('breadcrumb')
|
|
@yield('breadcrumb')
|
|
@else
|
|
<span class="navbar-text text-white">
|
|
<i class="fas fa-home me-1"></i>
|
|
@yield('title', 'Dashboard')
|
|
</span>
|
|
@endif
|
|
</div>
|
|
|
|
{{-- User actions --}}
|
|
<div class="navbar-nav">
|
|
{{-- Notifiche --}}
|
|
<div class="nav-item dropdown">
|
|
<a class="nav-link dropdown-toggle text-white" href="#" role="button" data-bs-toggle="dropdown">
|
|
<i class="fas fa-bell"></i>
|
|
<span class="badge bg-danger rounded-pill">3</span>
|
|
</a>
|
|
<ul class="dropdown-menu dropdown-menu-end">
|
|
<li><h6 class="dropdown-header">Notifiche</h6></li>
|
|
<li><a class="dropdown-item" href="#"><i class="fas fa-info-circle text-info me-2"></i>Nuovo pagamento</a></li>
|
|
<li><a class="dropdown-item" href="#"><i class="fas fa-exclamation-triangle text-warning me-2"></i>Fattura in scadenza</a></li>
|
|
<li><hr class="dropdown-divider"></li>
|
|
<li><a class="dropdown-item text-center" href="#">Vedi tutte</a></li>
|
|
</ul>
|
|
</div>
|
|
|
|
{{-- User menu --}}
|
|
<div class="nav-item dropdown">
|
|
<a class="nav-link dropdown-toggle text-white" href="#" role="button" data-bs-toggle="dropdown">
|
|
<i class="fas fa-user-circle me-1"></i>
|
|
{{ auth()->user()->name ?? 'Utente' }}
|
|
</a>
|
|
<ul class="dropdown-menu dropdown-menu-end">
|
|
<li><h6 class="dropdown-header">{{ ucfirst(str_replace('_', ' ', $userRole ?? 'user')) }}</h6></li>
|
|
<li><a class="dropdown-item" href="#"><i class="fas fa-user me-2"></i>Profilo</a></li>
|
|
<li><a class="dropdown-item" href="#"><i class="fas fa-cog me-2"></i>Impostazioni</a></li>
|
|
@if($userPermissions['super_admin'] ?? false)
|
|
<li><hr class="dropdown-divider"></li>
|
|
<li><a class="dropdown-item text-muted disabled" href="#" title="Impersonifica - Funzionalità in sviluppo"><i class="fas fa-mask me-2"></i>Impersonifica</a></li>
|
|
@endif
|
|
<li><hr class="dropdown-divider"></li>
|
|
<li>
|
|
<form method="POST" action="{{ route('logout') }}" class="d-inline">
|
|
@csrf
|
|
<button type="submit" class="dropdown-item">
|
|
<i class="fas fa-sign-out-alt me-2"></i>Logout
|
|
</button>
|
|
</form>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
{{-- Page content --}}
|
|
<div class="container-fluid p-4">
|
|
{{-- Breadcrumb interno --}}
|
|
@hasSection('breadcrumb-internal')
|
|
<div class="breadcrumb-netgescon">
|
|
@yield('breadcrumb-internal')
|
|
</div>
|
|
@endif
|
|
|
|
{{-- Alert messages --}}
|
|
@if (session('success'))
|
|
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
|
<i class="fas fa-check-circle me-2"></i>
|
|
{{ session('success') }}
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
|
</div>
|
|
@endif
|
|
|
|
@if (session('error'))
|
|
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
|
<i class="fas fa-exclamation-circle me-2"></i>
|
|
{{ session('error') }}
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
|
</div>
|
|
@endif
|
|
|
|
@if (session('warning'))
|
|
<div class="alert alert-warning alert-dismissible fade show" role="alert">
|
|
<i class="fas fa-exclamation-triangle me-2"></i>
|
|
{{ session('warning') }}
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
|
</div>
|
|
@endif
|
|
|
|
{{-- Main content --}}
|
|
@yield('content')
|
|
</div>
|
|
</div>
|
|
<div class="offcanvas offcanvas-start bg-warning" tabindex="-1" id="mobile-sidebar" aria-labelledby="mobileSidebarLabel">
|
|
<div class="offcanvas-header border-bottom border-primary">
|
|
<h5 class="offcanvas-title" id="mobileSidebarLabel">Menu</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label="Close"></button>
|
|
</div>
|
|
<div class="offcanvas-body p-0">
|
|
@include('components.menu.sidebar')
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Main Content -->
|
|
<div class="flex-fill d-flex flex-column">
|
|
<!-- Navigation con hamburger menu per mobile -->
|
|
<nav class="navbar navbar-expand-lg navbar-light bg-white shadow-sm border-bottom">
|
|
<div class="container-fluid">
|
|
<!-- MOBILE: Hamburger menu button -->
|
|
<button class="btn btn-outline-primary d-md-none me-3" type="button" data-bs-toggle="offcanvas" data-bs-target="#mobile-sidebar" aria-controls="mobile-sidebar">
|
|
<i class="fas fa-bars"></i>
|
|
</button>
|
|
|
|
<!-- Logo -->
|
|
<a class="navbar-brand fw-bold" href="{{ auth()->user()->hasRole('super-admin') ? route('superadmin.dashboard') : route('admin.dashboard') }}">
|
|
NetGesCon
|
|
@if(auth()->user()->hasRole('super-admin'))
|
|
<span class="badge bg-danger ms-1">Super</span>
|
|
@elseif(auth()->user()->hasRole('amministratore'))
|
|
<span class="badge bg-primary ms-1">Admin</span>
|
|
@endif
|
|
</a>
|
|
|
|
<!-- Settings Dropdown (sempre visibile) -->
|
|
<div class="d-flex align-items-center">
|
|
<!-- Dark Mode Toggle -->
|
|
<button id="dark-mode-toggle" class="btn btn-outline-secondary me-3" title="Modalità scura">
|
|
<i class="fas fa-moon" id="dark-icon"></i>
|
|
</button>
|
|
|
|
<!-- User dropdown -->
|
|
<div class="dropdown">
|
|
<button class="btn btn-outline-primary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
|
<i class="fas fa-user me-1"></i>
|
|
{{ Auth::user()->name }}
|
|
</button>
|
|
<ul class="dropdown-menu dropdown-menu-end">
|
|
<li><a class="dropdown-item" href="{{ route('profile.edit') }}">
|
|
<i class="fas fa-user-edit me-2"></i>{{ __('Profile') }}
|
|
</a></li>
|
|
<li><hr class="dropdown-divider"></li>
|
|
<li>
|
|
<form method="POST" action="{{ route('logout') }}" class="m-0">
|
|
@csrf
|
|
<button type="submit" class="dropdown-item text-danger">
|
|
<i class="fas fa-sign-out-alt me-2"></i>{{ __('Log Out') }}
|
|
</button>
|
|
</form>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
<x-dropdown align="right" width="48">
|
|
<x-slot name="trigger">
|
|
<button class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-500 dark:text-gray-400 bg-white dark:bg-gray-800 hover:text-gray-700 dark:hover:text-gray-300 focus:outline-none transition ease-in-out duration-150">
|
|
<div class="flex items-center">
|
|
<div class="mr-2">
|
|
<!-- Indicatore ruolo con colore -->
|
|
@if(auth()->user()->hasRole('super-admin'))
|
|
<div class="w-3 h-3 bg-red-500 rounded-full"></div>
|
|
@elseif(auth()->user()->hasRole('amministratore'))
|
|
<div class="w-3 h-3 bg-blue-500 rounded-full"></div>
|
|
@else
|
|
<div class="w-3 h-3 bg-gray-500 rounded-full"></div>
|
|
@endif
|
|
</div>
|
|
<div>{{ Auth::user()->name }}</div>
|
|
</div>
|
|
|
|
<div class="ml-1">
|
|
<svg class="fill-current h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
|
|
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
|
|
</svg>
|
|
</div>
|
|
</button>
|
|
</x-slot>
|
|
|
|
<x-slot name="content">
|
|
<x-dropdown-link :href="route('profile.edit')">
|
|
{{ __('Profile') }}
|
|
</x-dropdown-link>
|
|
|
|
<!-- Mostra ruoli utente -->
|
|
<div class="px-4 py-2 text-xs text-gray-400 border-t border-gray-200">
|
|
Ruoli: {{ auth()->user()->roles->pluck('name')->join(', ') }}
|
|
</div>
|
|
|
|
<!-- Authentication -->
|
|
<form method="POST" action="{{ route('logout') }}">
|
|
@csrf
|
|
<x-dropdown-link :href="route('logout')"
|
|
onclick="event.preventDefault();
|
|
this.closest('form').submit();">
|
|
{{ __('Log Out') }}
|
|
</x-dropdown-link>
|
|
</form>
|
|
</x-slot>
|
|
</x-dropdown>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
<!-- Page Content -->
|
|
<main class="flex-1 overflow-x-hidden overflow-y-auto bg-gray-100 dark:bg-gray-900 p-4 sm:p-6">
|
|
@yield('content')
|
|
</main>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- JavaScript per gestione responsive e dark mode -->
|
|
<script>
|
|
// Toggle mobile sidebar
|
|
document.getElementById('mobile-menu-button').addEventListener('click', function() {
|
|
const sidebar = document.getElementById('mobile-sidebar');
|
|
const overlay = document.getElementById('mobile-overlay');
|
|
|
|
sidebar.classList.remove('-translate-x-full');
|
|
overlay.classList.remove('opacity-0', 'pointer-events-none');
|
|
overlay.classList.add('opacity-100');
|
|
<!-- Page Content -->
|
|
<main class="flex-fill bg-light p-4">
|
|
@yield('content')
|
|
</main>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- JavaScript per gestione responsive e dark mode -->
|
|
<script>
|
|
// Dark mode toggle
|
|
document.getElementById('dark-mode-toggle').addEventListener('click', function() {
|
|
document.body.classList.toggle('bg-dark');
|
|
document.body.classList.toggle('text-light');
|
|
const icon = document.getElementById('dark-icon');
|
|
icon.classList.toggle('fa-moon');
|
|
icon.classList.toggle('fa-sun');
|
|
|
|
// Salva preferenza
|
|
const isDark = document.body.classList.contains('bg-dark');
|
|
localStorage.setItem('darkMode', isDark ? 'enabled' : 'disabled');
|
|
});
|
|
|
|
// Carica preferenza dark mode
|
|
if (localStorage.getItem('darkMode') === 'enabled') {
|
|
document.body.classList.add('bg-dark', 'text-light');
|
|
document.getElementById('dark-icon').classList.replace('fa-moon', 'fa-sun');
|
|
}
|
|
|
|
// Mobile menu toggle
|
|
const mobileMenuToggle = document.getElementById('mobile-menu-toggle');
|
|
if (mobileMenuToggle) {
|
|
mobileMenuToggle.addEventListener('click', function() {
|
|
const mobileSidebar = new bootstrap.Offcanvas(document.getElementById('mobile-sidebar'));
|
|
mobileSidebar.show();
|
|
});
|
|
}
|
|
|
|
// Toggle desktop sidebar
|
|
const toggleSidebar = document.getElementById('toggle-sidebar');
|
|
if (toggleSidebar) {
|
|
toggleSidebar.addEventListener('click', function() {
|
|
const sidebar = document.getElementById('sidebar-menu');
|
|
const showBtn = document.getElementById('show-sidebar');
|
|
|
|
if (sidebar) sidebar.style.display = 'none';
|
|
if (showBtn) showBtn.style.display = 'block';
|
|
});
|
|
}
|
|
|
|
const showSidebar = document.getElementById('show-sidebar');
|
|
if (showSidebar) {
|
|
showSidebar.addEventListener('click', function() {
|
|
const sidebar = document.getElementById('sidebar-menu');
|
|
const showBtn = document.getElementById('show-sidebar');
|
|
|
|
if (sidebar) sidebar.style.display = 'flex';
|
|
if (showBtn) showBtn.style.display = 'none';
|
|
});
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|