f57ae068b9
SiteSettingsService : persistance JSON dans storage/app/site_settings.json
(pas de migration DB — survit aux mises à jour sans table supplémentaire)
Logo :
- Upload admin (PNG/JPG/SVG/WebP, max 2 Mo) → storage/app/public/site/logo.{ext}
- Favicon <link rel="icon"> injecté dans app.blade.php et guest.blade.php
- Logo affiché dans la barre de navigation (h-8, object-contain)
- Logo affiché sur la page de connexion (guest layout)
- Page d'accueil welcome.blade.php entièrement refaite : logo + bouton connexion
(remplacement du template Laravel par défaut)
- Suppression du logo possible depuis Admin > Paramètres du site
Inscriptions :
- Désactivées par défaut (registration_enabled=false dans site_settings.json)
- RegisteredUserController : redirige vers /login si inscription désactivée
(GET /register → redirect + message ; POST /register → abort 403)
- Page d'accueil : bouton "Créer un compte" masqué si inscriptions désactivées
- Admin > Paramètres du site : toggle checkbox pour activer/désactiver
AppServiceProvider : partage $siteLogoUrl et $registrationEnabled avec toutes les vues
Navigation : lien "Paramètres du site" en bas du menu Administration
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
200 lines
12 KiB
PHP
200 lines
12 KiB
PHP
<nav x-data="{ open: false }" class="bg-white border-b border-gray-100">
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div class="flex justify-between h-16">
|
|
<div class="flex">
|
|
<!-- Logo -->
|
|
<div class="shrink-0 flex items-center">
|
|
<a href="{{ route('dashboard') }}" class="flex items-center">
|
|
@if($siteLogoUrl)
|
|
<img src="{{ $siteLogoUrl }}" alt="{{ config('app.name') }}"
|
|
class="h-8 w-auto object-contain max-w-[160px]">
|
|
@else
|
|
<span class="font-semibold text-gray-800 text-lg">{{ config('app.name') }}</span>
|
|
@endif
|
|
</a>
|
|
</div>
|
|
|
|
<!-- Navigation Links -->
|
|
<div class="hidden space-x-8 sm:-my-px sm:ms-10 sm:flex">
|
|
<x-nav-link :href="route('dashboard')" :active="request()->routeIs('dashboard')">
|
|
Tableau de bord
|
|
</x-nav-link>
|
|
|
|
<x-nav-link :href="route('sources.index')" :active="request()->routeIs('sources.*') && !request()->routeIs('sources.releves.*')">
|
|
Sources
|
|
</x-nav-link>
|
|
|
|
<x-nav-link :href="route('lieux.index')" :active="request()->routeIs('lieux.*')">
|
|
Lieux
|
|
</x-nav-link>
|
|
|
|
<x-nav-link :href="route('recherche')" :active="request()->routeIs('recherche')">
|
|
Recherche
|
|
</x-nav-link>
|
|
|
|
@if(auth()->user()->isSectionManager())
|
|
<!-- Menu Administration -->
|
|
<div class="relative hidden sm:flex sm:items-center" x-data="{ adminOpen: false }">
|
|
<button @click="adminOpen = !adminOpen"
|
|
class="inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium leading-5 transition duration-150 ease-in-out
|
|
{{ request()->routeIs('admin.*') ? 'border-indigo-400 text-gray-900' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300' }}">
|
|
Administration
|
|
<svg class="ms-1 h-4 w-4 fill-current" 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>
|
|
</button>
|
|
|
|
<div x-show="adminOpen" @click.outside="adminOpen = false" x-cloak
|
|
class="absolute top-full left-0 mt-1 w-56 bg-white rounded-md shadow-lg border border-gray-100 z-50">
|
|
@if(auth()->user()->isAdmin())
|
|
<a href="{{ route('admin.dashboard') }}"
|
|
class="block px-4 py-2 text-sm font-medium text-indigo-700 hover:bg-indigo-50 border-b border-gray-100">
|
|
Tableau de bord admin
|
|
</a>
|
|
<a href="{{ route('admin.utilisateurs.index') }}"
|
|
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-50">Utilisateurs</a>
|
|
@endif
|
|
<a href="{{ route('admin.sections.index') }}"
|
|
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-50">Sections</a>
|
|
@if(auth()->user()->isAdmin())
|
|
<a href="{{ route('admin.depots.index') }}"
|
|
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-50">Dépôts d'archives</a>
|
|
<a href="{{ route('admin.source-types.index') }}"
|
|
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-50">Types de sources</a>
|
|
<a href="{{ route('admin.lieu-types.index') }}"
|
|
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-50">Types de lieux</a>
|
|
<div class="border-t border-gray-100 mt-1 pt-1">
|
|
<a href="{{ route('admin.parametres') }}"
|
|
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-50">Paramètres du site</a>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Cloche notifications -->
|
|
<div class="hidden sm:flex sm:items-center sm:ms-4">
|
|
@php $unreadCount = auth()->user()->unreadNotifications->count(); @endphp
|
|
<a href="{{ route('notifications.index') }}"
|
|
class="relative p-2 text-gray-500 hover:text-indigo-600 transition-colors"
|
|
title="Notifications">
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
|
d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"/>
|
|
</svg>
|
|
@if($unreadCount > 0)
|
|
<span class="absolute top-1 right-1 inline-flex items-center justify-center w-4 h-4 text-xs font-bold text-white bg-red-500 rounded-full">
|
|
{{ $unreadCount > 9 ? '9+' : $unreadCount }}
|
|
</span>
|
|
@endif
|
|
</a>
|
|
</div>
|
|
|
|
<!-- Settings Dropdown -->
|
|
<div class="hidden sm:flex sm:items-center sm:ms-2">
|
|
<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 bg-white hover:text-gray-700 focus:outline-none transition ease-in-out duration-150">
|
|
<div>{{ Auth::user()->name }}</div>
|
|
<div class="ms-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">
|
|
<div class="px-4 py-2 text-xs text-gray-400 border-b border-gray-100">
|
|
{{ Auth::user()->role->label() }}
|
|
</div>
|
|
<x-dropdown-link :href="route('profile.edit')">
|
|
Mon profil
|
|
</x-dropdown-link>
|
|
<form method="POST" action="{{ route('logout') }}">
|
|
@csrf
|
|
<x-dropdown-link :href="route('logout')"
|
|
onclick="event.preventDefault(); this.closest('form').submit();">
|
|
Se déconnecter
|
|
</x-dropdown-link>
|
|
</form>
|
|
</x-slot>
|
|
</x-dropdown>
|
|
</div>
|
|
|
|
<!-- Hamburger -->
|
|
<div class="-me-2 flex items-center sm:hidden">
|
|
<button @click="open = ! open" class="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none transition duration-150 ease-in-out">
|
|
<svg class="h-6 w-6" stroke="currentColor" fill="none" viewBox="0 0 24 24">
|
|
<path :class="{'hidden': open, 'inline-flex': ! open }" class="inline-flex" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
|
|
<path :class="{'hidden': ! open, 'inline-flex': open }" class="hidden" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Responsive Navigation Menu -->
|
|
<div :class="{'block': open, 'hidden': ! open}" class="hidden sm:hidden">
|
|
<div class="pt-2 pb-3 space-y-1">
|
|
<x-responsive-nav-link :href="route('dashboard')" :active="request()->routeIs('dashboard')">
|
|
Tableau de bord
|
|
</x-responsive-nav-link>
|
|
<x-responsive-nav-link :href="route('sources.index')" :active="request()->routeIs('sources.*')">
|
|
Sources
|
|
</x-responsive-nav-link>
|
|
<x-responsive-nav-link :href="route('lieux.index')" :active="request()->routeIs('lieux.*')">
|
|
Lieux
|
|
</x-responsive-nav-link>
|
|
<x-responsive-nav-link :href="route('recherche')" :active="request()->routeIs('recherche')">
|
|
Recherche
|
|
</x-responsive-nav-link>
|
|
@if(auth()->user()->isSectionManager())
|
|
@if(auth()->user()->isAdmin())
|
|
<x-responsive-nav-link :href="route('admin.dashboard')" :active="request()->routeIs('admin.dashboard')">
|
|
Tableau de bord admin
|
|
</x-responsive-nav-link>
|
|
<x-responsive-nav-link :href="route('admin.utilisateurs.index')" :active="request()->routeIs('admin.utilisateurs.*')">
|
|
Utilisateurs
|
|
</x-responsive-nav-link>
|
|
@endif
|
|
<x-responsive-nav-link :href="route('admin.sections.index')" :active="request()->routeIs('admin.sections.*')">
|
|
Sections
|
|
</x-responsive-nav-link>
|
|
@if(auth()->user()->isAdmin())
|
|
<x-responsive-nav-link :href="route('admin.depots.index')" :active="request()->routeIs('admin.depots.*')">
|
|
Dépôts d'archives
|
|
</x-responsive-nav-link>
|
|
<x-responsive-nav-link :href="route('admin.source-types.index')" :active="request()->routeIs('admin.source-types.*')">
|
|
Types de sources
|
|
</x-responsive-nav-link>
|
|
<x-responsive-nav-link :href="route('admin.lieu-types.index')" :active="request()->routeIs('admin.lieu-types.*')">
|
|
Types de lieux
|
|
</x-responsive-nav-link>
|
|
@endif
|
|
@endif
|
|
</div>
|
|
|
|
<!-- Responsive Settings Options -->
|
|
<div class="pt-4 pb-1 border-t border-gray-200">
|
|
<div class="px-4">
|
|
<div class="font-medium text-base text-gray-800">{{ Auth::user()->name }}</div>
|
|
<div class="font-medium text-sm text-gray-500">{{ Auth::user()->email }}</div>
|
|
<div class="text-xs text-gray-400">{{ Auth::user()->role->label() }}</div>
|
|
</div>
|
|
<div class="mt-3 space-y-1">
|
|
<x-responsive-nav-link :href="route('profile.edit')">Mon profil</x-responsive-nav-link>
|
|
<form method="POST" action="{{ route('logout') }}">
|
|
@csrf
|
|
<x-responsive-nav-link :href="route('logout')"
|
|
onclick="event.preventDefault(); this.closest('form').submit();">
|
|
Se déconnecter
|
|
</x-responsive-nav-link>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</nav>
|