Mode sombre, option désactivation mises à jour, user-picker avec recherche
- Dark mode complet : darkMode:'class' Tailwind, sélecteur clair/sombre/auto dans la navigation (mémorisé dans localStorage, sans flash au chargement) ; 53 vues et 8 composants Breeze mis à jour avec classes dark: - Composant user-picker : fenêtre modale avec recherche temps réel (nom/email) remplace les <select> d'ajout de membres dans sections et sources - Paramètres : option "Désactiver la vérification automatique des mises à jour" (case à cochage auto-soumise, route POST parametres/updates) - Panneau "Paramètres généraux" remonté en tête de la page de paramètres - README recentré sur l'installation manuelle hébergement PHP+MySQL - VERSION 1.0.1 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}" class="">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
@@ -11,6 +11,20 @@
|
||||
<link rel="icon" href="{{ $siteLogoUrl }}">
|
||||
@endif
|
||||
|
||||
<!-- Dark mode init — must run before first paint to avoid flash -->
|
||||
<script>
|
||||
(function () {
|
||||
var t = localStorage.getItem('colorTheme') || 'auto';
|
||||
var dark = t === 'dark' || (t === 'auto' && window.matchMedia('(prefers-color-scheme: dark)').matches);
|
||||
document.documentElement.classList.toggle('dark', dark);
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', function (e) {
|
||||
if ((localStorage.getItem('colorTheme') || 'auto') === 'auto') {
|
||||
document.documentElement.classList.toggle('dark', e.matches);
|
||||
}
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
<!-- 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" />
|
||||
@@ -18,13 +32,13 @@
|
||||
<!-- Scripts -->
|
||||
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
||||
</head>
|
||||
<body class="font-sans antialiased">
|
||||
<div class="min-h-screen bg-gray-100">
|
||||
<body class="font-sans antialiased bg-gray-100 dark:bg-gray-900 text-gray-900 dark:text-gray-100">
|
||||
<div class="min-h-screen">
|
||||
@include('layouts.navigation')
|
||||
|
||||
<!-- Page Heading -->
|
||||
@isset($header)
|
||||
<header class="bg-white shadow">
|
||||
<header class="bg-white dark:bg-gray-800 shadow dark:shadow-gray-900/50">
|
||||
<div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
|
||||
{{ $header }}
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}" class="">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
@@ -11,6 +11,20 @@
|
||||
<link rel="icon" href="{{ $siteLogoUrl }}">
|
||||
@endif
|
||||
|
||||
<!-- Dark mode init -->
|
||||
<script>
|
||||
(function () {
|
||||
var t = localStorage.getItem('colorTheme') || 'auto';
|
||||
var dark = t === 'dark' || (t === 'auto' && window.matchMedia('(prefers-color-scheme: dark)').matches);
|
||||
document.documentElement.classList.toggle('dark', dark);
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', function (e) {
|
||||
if ((localStorage.getItem('colorTheme') || 'auto') === 'auto') {
|
||||
document.documentElement.classList.toggle('dark', e.matches);
|
||||
}
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
<!-- 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" />
|
||||
@@ -18,19 +32,19 @@
|
||||
<!-- Scripts -->
|
||||
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
||||
</head>
|
||||
<body class="font-sans text-gray-900 antialiased">
|
||||
<div class="min-h-screen flex flex-col sm:justify-center items-center pt-6 sm:pt-0 bg-gray-100">
|
||||
<body class="font-sans text-gray-900 dark:text-gray-100 antialiased">
|
||||
<div class="min-h-screen flex flex-col sm:justify-center items-center pt-6 sm:pt-0 bg-gray-100 dark:bg-gray-900">
|
||||
<div class="mb-2">
|
||||
<a href="/">
|
||||
@if($siteLogoUrl)
|
||||
<img src="{{ $siteLogoUrl }}" alt="{{ config('app.name') }}" class="h-16 w-auto object-contain">
|
||||
@else
|
||||
<x-application-logo class="w-16 h-16 fill-current text-gray-400" />
|
||||
<x-application-logo class="w-16 h-16 fill-current text-gray-400 dark:text-gray-500" />
|
||||
@endif
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="w-full sm:max-w-md mt-6 px-6 py-4 bg-white shadow-md overflow-hidden sm:rounded-lg">
|
||||
<div class="w-full sm:max-w-md mt-6 px-6 py-4 bg-white dark:bg-gray-800 shadow-md dark:shadow-gray-900/50 overflow-hidden sm:rounded-lg">
|
||||
{{ $slot }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<nav x-data="{ open: false }" class="bg-white border-b border-gray-100">
|
||||
<nav x-data="{ open: false }" class="bg-white dark:bg-gray-800 border-b border-gray-100 dark:border-gray-700">
|
||||
<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 — max-h contraint sur l'image directement, sans chaîne h-full -->
|
||||
<!-- Logo -->
|
||||
<div class="shrink-0 flex items-center">
|
||||
<a href="{{ route('dashboard') }}" class="flex items-center">
|
||||
@if($siteLogoUrl)
|
||||
@@ -10,7 +10,7 @@
|
||||
class="block w-auto object-contain"
|
||||
style="max-height: 40px; max-width: 200px;">
|
||||
@else
|
||||
<span class="font-semibold text-gray-800 text-lg">{{ config('app.name') }}</span>
|
||||
<span class="font-semibold text-gray-800 dark:text-gray-200 text-lg">{{ config('app.name') }}</span>
|
||||
@endif
|
||||
</a>
|
||||
</div>
|
||||
@@ -34,12 +34,11 @@
|
||||
</x-nav-link>
|
||||
|
||||
@if(auth()->user()->isSectionManager())
|
||||
<!-- Menu Administration — utilise le composant x-dropdown (même positionnement que le menu utilisateur) -->
|
||||
<div class="hidden sm:flex sm:items-center">
|
||||
<x-dropdown align="left" width="w-56">
|
||||
<x-slot name="trigger">
|
||||
<button 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' }}">
|
||||
{{ request()->routeIs('admin.*') ? 'border-indigo-400 text-gray-900 dark:text-white' : 'border-transparent text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 hover:border-gray-300 dark:hover:border-gray-600' }}">
|
||||
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"/>
|
||||
@@ -70,7 +69,7 @@
|
||||
<x-dropdown-link :href="route('admin.lieu-types.index')">
|
||||
Types de lieux
|
||||
</x-dropdown-link>
|
||||
<div class="border-t border-gray-100 my-1"></div>
|
||||
<div class="border-t border-gray-100 dark:border-gray-700 my-1"></div>
|
||||
<x-dropdown-link :href="route('admin.parametres')">
|
||||
Paramètres du site
|
||||
</x-dropdown-link>
|
||||
@@ -82,11 +81,53 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Cloche notifications -->
|
||||
<div class="hidden sm:flex sm:items-center sm:ms-4">
|
||||
<!-- Right side: theme toggle + notifications + user menu -->
|
||||
<div class="hidden sm:flex sm:items-center sm:gap-1">
|
||||
|
||||
<!-- Sélecteur de thème -->
|
||||
<div x-data="{
|
||||
theme: localStorage.getItem('colorTheme') || 'auto',
|
||||
apply(t) {
|
||||
this.theme = t;
|
||||
localStorage.setItem('colorTheme', t);
|
||||
var dark = t === 'dark' || (t === 'auto' && window.matchMedia('(prefers-color-scheme: dark)').matches);
|
||||
document.documentElement.classList.toggle('dark', dark);
|
||||
}
|
||||
}" class="flex items-center">
|
||||
<div class="flex items-center bg-gray-100 dark:bg-gray-700 rounded-full p-0.5 gap-0.5">
|
||||
<!-- Clair -->
|
||||
<button @click="apply('light')"
|
||||
:class="theme === 'light' ? 'bg-white dark:bg-gray-600 shadow text-gray-800 dark:text-gray-100' : 'text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:hover:text-gray-300'"
|
||||
class="p-1.5 rounded-full transition-all" title="Mode clair">
|
||||
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364-6.364l-.707.707M6.343 17.657l-.707.707M17.657 17.657l-.707-.707M6.343 6.343l-.707-.707M12 7a5 5 0 100 10A5 5 0 0012 7z"/>
|
||||
</svg>
|
||||
</button>
|
||||
<!-- Automatique -->
|
||||
<button @click="apply('auto')"
|
||||
:class="theme === 'auto' ? 'bg-white dark:bg-gray-600 shadow text-gray-800 dark:text-gray-100' : 'text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:hover:text-gray-300'"
|
||||
class="p-1.5 rounded-full transition-all" title="Automatique (système)">
|
||||
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"/>
|
||||
</svg>
|
||||
</button>
|
||||
<!-- Sombre -->
|
||||
<button @click="apply('dark')"
|
||||
:class="theme === 'dark' ? 'bg-white dark:bg-gray-600 shadow text-gray-800 dark:text-gray-100' : 'text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:hover:text-gray-300'"
|
||||
class="p-1.5 rounded-full transition-all" title="Mode sombre">
|
||||
<svg class="w-3.5 h-3.5" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Notifications -->
|
||||
@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"
|
||||
class="relative p-2 text-gray-500 dark:text-gray-400 hover:text-indigo-600 dark:hover:text-indigo-400 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"
|
||||
@@ -98,13 +139,11 @@
|
||||
</span>
|
||||
@endif
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Menu utilisateur (Profil / Déconnexion) -->
|
||||
<div class="hidden sm:flex sm:items-center sm:ms-2">
|
||||
<!-- Menu utilisateur -->
|
||||
<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">
|
||||
<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-200 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">
|
||||
@@ -115,7 +154,7 @@
|
||||
</x-slot>
|
||||
|
||||
<x-slot name="content">
|
||||
<div class="px-4 py-2 text-xs text-gray-400 border-b border-gray-100">
|
||||
<div class="px-4 py-2 text-xs text-gray-400 dark:text-gray-500 border-b border-gray-100 dark:border-gray-700">
|
||||
{{ Auth::user()->role->label() }}
|
||||
</div>
|
||||
<x-dropdown-link :href="route('profile.edit')">
|
||||
@@ -134,7 +173,7 @@
|
||||
|
||||
<!-- Hamburger (mobile) -->
|
||||
<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">
|
||||
<button @click="open = ! open" class="inline-flex items-center justify-center p-2 rounded-md text-gray-400 dark:text-gray-500 hover:text-gray-500 dark:hover:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 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" />
|
||||
@@ -189,12 +228,52 @@
|
||||
</div>
|
||||
|
||||
<!-- Options utilisateur (mobile) -->
|
||||
<div class="pt-4 pb-1 border-t border-gray-200">
|
||||
<div class="pt-4 pb-1 border-t border-gray-200 dark:border-gray-700">
|
||||
<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 class="font-medium text-base text-gray-800 dark:text-gray-200">{{ Auth::user()->name }}</div>
|
||||
<div class="font-medium text-sm text-gray-500 dark:text-gray-400">{{ Auth::user()->email }}</div>
|
||||
<div class="text-xs text-gray-400 dark:text-gray-500">{{ Auth::user()->role->label() }}</div>
|
||||
</div>
|
||||
|
||||
<!-- Sélecteur de thème mobile -->
|
||||
<div x-data="{
|
||||
theme: localStorage.getItem('colorTheme') || 'auto',
|
||||
apply(t) {
|
||||
this.theme = t;
|
||||
localStorage.setItem('colorTheme', t);
|
||||
var dark = t === 'dark' || (t === 'auto' && window.matchMedia('(prefers-color-scheme: dark)').matches);
|
||||
document.documentElement.classList.toggle('dark', dark);
|
||||
}
|
||||
}" class="px-4 pt-3 pb-1">
|
||||
<p class="text-xs text-gray-400 dark:text-gray-500 mb-2">Apparence</p>
|
||||
<div class="flex gap-2">
|
||||
<button @click="apply('light')"
|
||||
:class="theme === 'light' ? 'bg-indigo-50 dark:bg-indigo-900/50 text-indigo-700 dark:text-indigo-300 border-indigo-300 dark:border-indigo-600' : 'border-gray-200 dark:border-gray-600 text-gray-600 dark:text-gray-400'"
|
||||
class="flex-1 flex items-center justify-center gap-1.5 py-1.5 text-xs border rounded-md transition-colors">
|
||||
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364-6.364l-.707.707M6.343 17.657l-.707.707M17.657 17.657l-.707-.707M6.343 6.343l-.707-.707M12 7a5 5 0 100 10A5 5 0 0012 7z"/>
|
||||
</svg>
|
||||
Clair
|
||||
</button>
|
||||
<button @click="apply('auto')"
|
||||
:class="theme === 'auto' ? 'bg-indigo-50 dark:bg-indigo-900/50 text-indigo-700 dark:text-indigo-300 border-indigo-300 dark:border-indigo-600' : 'border-gray-200 dark:border-gray-600 text-gray-600 dark:text-gray-400'"
|
||||
class="flex-1 flex items-center justify-center gap-1.5 py-1.5 text-xs border rounded-md transition-colors">
|
||||
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"/>
|
||||
</svg>
|
||||
Auto
|
||||
</button>
|
||||
<button @click="apply('dark')"
|
||||
:class="theme === 'dark' ? 'bg-indigo-50 dark:bg-indigo-900/50 text-indigo-700 dark:text-indigo-300 border-indigo-300 dark:border-indigo-600' : 'border-gray-200 dark:border-gray-600 text-gray-600 dark:text-gray-400'"
|
||||
class="flex-1 flex items-center justify-center gap-1.5 py-1.5 text-xs border rounded-md transition-colors">
|
||||
<svg class="w-3.5 h-3.5" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"/>
|
||||
</svg>
|
||||
Sombre
|
||||
</button>
|
||||
</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') }}">
|
||||
|
||||
Reference in New Issue
Block a user