netgescon-master/netgescon-laravel/resources/views/layouts/app-universal.blade.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>