170 lines
6.9 KiB
TypeScript
170 lines
6.9 KiB
TypeScript
"use client"
|
|
|
|
import { useState, useRef, useEffect } from "react"
|
|
import { Icon, addCollection } from "@iconify/react"
|
|
import { icons as mdiIcons } from "@iconify-json/mdi"
|
|
import { Menu, Search, SlidersHorizontal, Pencil } from "lucide-react"
|
|
import { Button } from "@/components/ui/button"
|
|
|
|
addCollection(mdiIcons)
|
|
import { Input } from "@/components/ui/input"
|
|
import { UltiMailLogo } from "@/components/ultimail-logo"
|
|
import { cn } from "@/lib/utils"
|
|
|
|
interface HeaderProps {
|
|
onToggleSidebar: () => void
|
|
/** Match `<main>` horizontal offset (same width as sidebar rail spacer). */
|
|
sidebarCollapsed: boolean
|
|
isXs?: boolean
|
|
}
|
|
|
|
const googleApps = [
|
|
{ name: "Compte", icon: "/compte-mark.svg" },
|
|
{ name: "Agenda", icon: "/agenda-mark.svg" },
|
|
{ name: "Photos", icon: "/photos-mark.svg" },
|
|
{ name: "Ultimail", icon: "/brand/ultimail-header-icon.png" },
|
|
{ name: "UltiDrive", icon: "/ultidrive-mark.svg" },
|
|
{ name: "UltiMeet", icon: "/ultimeet-mark.svg" },
|
|
{ name: "Administration", icon: "/admin-mark.svg" },
|
|
{ name: "OpenMaps", icon: "/openstreetmap-mark.svg" },
|
|
{ name: "Mistral", icon: "/mistral-mark.svg" },
|
|
{ name: "Qwant", icon: "/qwant-mark.svg" },
|
|
{ name: "Ground News", icon: "/ground-news-mark.svg" },
|
|
]
|
|
|
|
export function Header({
|
|
onToggleSidebar,
|
|
sidebarCollapsed,
|
|
isXs = false,
|
|
}: HeaderProps) {
|
|
const [appsMenuOpen, setAppsMenuOpen] = useState(false)
|
|
const menuRef = useRef<HTMLDivElement>(null)
|
|
|
|
useEffect(() => {
|
|
function handleClickOutside(event: MouseEvent) {
|
|
if (menuRef.current && !menuRef.current.contains(event.target as Node)) {
|
|
setAppsMenuOpen(false)
|
|
}
|
|
}
|
|
document.addEventListener("mousedown", handleClickOutside)
|
|
return () => document.removeEventListener("mousedown", handleClickOutside)
|
|
}, [])
|
|
|
|
return (
|
|
<header className="flex h-16 w-full min-w-0 items-center gap-0 bg-app-canvas pl-0 pr-4 sm:gap-2">
|
|
{/* Rail width = page spacer so search left edge lines up with `<main>`. */}
|
|
<div
|
|
className={cn(
|
|
"flex h-full min-w-0 shrink-0 items-center",
|
|
isXs
|
|
? "w-auto justify-start gap-0 pl-2"
|
|
: sidebarCollapsed
|
|
? "w-[68px] justify-center px-0"
|
|
: "w-60 gap-2 pl-4"
|
|
)}
|
|
>
|
|
<Button variant="ghost" size="icon" className="shrink-0 text-gray-600" onClick={onToggleSidebar}>
|
|
<Menu className="h-5 w-5" />
|
|
</Button>
|
|
{!sidebarCollapsed && !isXs && (
|
|
<div className="flex min-w-0 items-center">
|
|
<UltiMailLogo variant="mark" className="h-8 w-8 shrink-0 sm:hidden" />
|
|
<UltiMailLogo className="min-h-8 shrink-0 hidden sm:flex" />
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
className="size-12 shrink-0 rounded-full border border-[#d3e3fd] bg-[#eaf1fb] text-gray-500 hover:bg-[#dfe9f7] sm:hidden"
|
|
aria-label="Rechercher dans les messages"
|
|
>
|
|
<Search className="size-5 shrink-0 ml-0.5" />
|
|
</Button>
|
|
<div className="hidden min-w-0 flex-1 max-w-3xl sm:flex">
|
|
<div className="relative flex w-full items-center">
|
|
<div className="absolute left-3 flex items-center text-gray-500">
|
|
<Search className="size-5 shrink-0 ml-0.5" />
|
|
</div>
|
|
<Input
|
|
type="text"
|
|
placeholder="Rechercher dans les messages"
|
|
className="h-12 w-full rounded-full border-0 bg-[#eaf1fb] pl-12 pr-12 text-sm focus-visible:ring-1 focus-visible:ring-blue-500 focus-visible:bg-white"
|
|
/>
|
|
<Button variant="ghost" size="icon" className="absolute right-2 text-gray-600">
|
|
<SlidersHorizontal className="h-5 w-5" />
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="ml-auto flex shrink-0 items-center gap-1 pl-4">
|
|
{sidebarCollapsed && (
|
|
<div className="mr-1 flex min-w-0 max-w-[min(100%,400px)] items-center pr-2">
|
|
<UltiMailLogo variant="mark" className="h-8 w-8 shrink-0 sm:hidden" />
|
|
<UltiMailLogo className="min-h-8 shrink-0 hidden sm:flex" />
|
|
</div>
|
|
)}
|
|
<Button variant="ghost" size="icon" className="hidden text-gray-600 sm:inline-flex" aria-label="Aide">
|
|
<Icon icon="mdi:help-circle-outline" className="size-6 shrink-0" aria-hidden />
|
|
</Button>
|
|
<Button variant="ghost" size="icon" className="text-gray-600" aria-label="Réglages">
|
|
<Icon icon="mdi:cog-outline" className="size-6 shrink-0" aria-hidden />
|
|
</Button>
|
|
|
|
{/* Google Apps Menu */}
|
|
<div className="relative hidden sm:block" ref={menuRef}>
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
className="text-gray-600"
|
|
aria-label="Applications"
|
|
onClick={() => setAppsMenuOpen(!appsMenuOpen)}
|
|
>
|
|
<Icon icon="mdi:view-grid-outline" className="size-6 shrink-0" aria-hidden />
|
|
</Button>
|
|
|
|
{appsMenuOpen && (
|
|
<div className="absolute right-0 top-12 z-50 w-96 rounded-2xl border border-gray-200 bg-white shadow-xl">
|
|
<div className="flex items-center justify-between p-4 border-b border-gray-100">
|
|
<span className="text-lg font-normal text-gray-800">Vos favoris</span>
|
|
<Button variant="ghost" size="icon" className="text-gray-600 h-8 w-8">
|
|
<Pencil className="h-4 w-4" />
|
|
</Button>
|
|
</div>
|
|
<div className="grid grid-cols-3 gap-1 p-3">
|
|
{googleApps.map((app) => (
|
|
<button
|
|
key={app.name}
|
|
className="flex flex-col items-center gap-2 rounded-lg p-3 hover:bg-gray-100 transition-colors"
|
|
>
|
|
<div className="h-10 w-10 flex items-center justify-center">
|
|
<img
|
|
src={app.icon}
|
|
alt={app.name}
|
|
className="h-10 w-10 object-contain"
|
|
onError={(e) => {
|
|
const target = e.target as HTMLImageElement
|
|
target.style.display = 'none'
|
|
target.parentElement!.innerHTML = `<div class="h-10 w-10 rounded-full bg-blue-500 flex items-center justify-center text-white font-medium">${app.name[0]}</div>`
|
|
}}
|
|
/>
|
|
</div>
|
|
<span className="text-xs text-gray-700 w-full text-center">{app.name}</span>
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
<Button variant="ghost" size="icon-lg" className="size-11 rounded-full overflow-hidden ml-2 p-0">
|
|
<div className="h-10 w-10 rounded-full bg-purple-500 flex items-center justify-center text-white text-base font-medium">
|
|
E
|
|
</div>
|
|
</Button>
|
|
</div>
|
|
</header>
|
|
)
|
|
}
|