Refonte UI : design system, logo, shell responsive et pages simples

- Nouveaux tokens (indigo/corail, statuts, plateformes) et mode sombre
- Logo et favicon Social Flow redessinés
- AppShell partagé : sidebar groupée (desktop) + barre de navigation basse (mobile)
- Suppression des pages mobiles dupliquées et des composants morts
- Tableau de bord, connexion, 404, calendrier, médiathèque, IA, statistiques

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ADkrVcVFTT14hbB148HYS
This commit is contained in:
Claude committed 2026-10-06 12:44:11 +00:00
1 parent 01315bf281
commit 155c3385c1
55 files changed
+1591 -6331

No files matched your search

+36
View File
@@ -0,0 +1,36 @@
import { useMutation, useQuery } from "@tanstack/react-query";
import { useLocation } from "wouter";
import { apiRequest, AUTH_MUTATION, queryClient } from "@/lib/queryClient";
import { useToast } from "@/hooks/use-toast";
export interface Session {
id: string;
username: string;
role: string;
}
/** Session courante (mise en cache par react-query, partagée par toute l'app). */
export function useSession() {
const query = useQuery<Session>({
queryKey: ["/api/auth/session"],
retry: false,
});
return { ...query, session: query.data, isAdmin: query.data?.role === "admin" };
}
export function useLogout() {
const [, setLocation] = useLocation();
const { toast } = useToast();
return useMutation({
mutationKey: [AUTH_MUTATION, "logout"],
mutationFn: async () => {
const res = await apiRequest("POST", "/api/auth/logout", {});
return await res.json();
},
onSuccess: () => {
queryClient.clear();
setLocation("/login");
toast({ title: "Déconnecté", description: "À bientôt !" });
},
});
}
-72
View File
@@ -1,72 +0,0 @@
import { useState, useEffect } from 'react';
/**
* Hook to detect if the user is on a mobile device
* Uses both media query and user agent for robust detection
*
* @param breakpoint - The max-width breakpoint for mobile (default: 768px)
* @returns boolean - true if mobile, false if desktop
*/
export function useIsMobile(breakpoint: number = 768): boolean {
const [isMobile, setIsMobile] = useState<boolean>(() => {
// Initial detection (SSR-safe)
if (typeof window === 'undefined') return false;
// Check media query
const mediaMatch = window.matchMedia(`(max-width: ${breakpoint}px)`).matches;
// Check user agent for mobile devices
const userAgent = navigator.userAgent.toLowerCase();
const mobileKeywords = ['android', 'webos', 'iphone', 'ipad', 'ipod', 'blackberry', 'windows phone'];
const isUserAgentMobile = mobileKeywords.some(keyword => userAgent.includes(keyword));
// Return true if either media query or user agent indicates mobile
return mediaMatch || isUserAgentMobile;
});
useEffect(() => {
// Create media query list
const mediaQueryList = window.matchMedia(`(max-width: ${breakpoint}px)`);
// Handler for media query changes
const handleChange = (e: MediaQueryListEvent) => {
setIsMobile(e.matches);
};
// Listen for changes (modern browsers)
if (mediaQueryList.addEventListener) {
mediaQueryList.addEventListener('change', handleChange);
} else {
// Fallback for older browsers
mediaQueryList.addListener(handleChange);
}
// Cleanup
return () => {
if (mediaQueryList.removeEventListener) {
mediaQueryList.removeEventListener('change', handleChange);
} else {
mediaQueryList.removeListener(handleChange);
}
};
}, [breakpoint]);
return isMobile;
}
/**
* Hook to detect device type with more granularity
* @returns object with device type information
*/
export function useDeviceType() {
const isMobile = useIsMobile(768);
const isTablet = useIsMobile(1024) && !useIsMobile(768);
const isDesktop = !useIsMobile(1024);
return {
isMobile,
isTablet,
isDesktop,
deviceType: isMobile ? 'mobile' : isTablet ? 'tablet' : 'desktop'
} as const;
}