170 lines
5.8 KiB
TypeScript
170 lines
5.8 KiB
TypeScript
"use client"
|
||
|
||
import { useState, useRef, useEffect, useCallback } from "react"
|
||
import {
|
||
Menu,
|
||
Search,
|
||
X,
|
||
Pencil,
|
||
Archive,
|
||
FolderInput,
|
||
Reply,
|
||
} from "lucide-react"
|
||
import { Button } from "@/components/ui/button"
|
||
import {
|
||
DropdownMenu,
|
||
DropdownMenuContent,
|
||
DropdownMenuTrigger,
|
||
} from "@/components/ui/dropdown-menu"
|
||
import { useComposeActions } from "@/lib/compose-context"
|
||
import { MoveToDropdownItems } from "@/components/gmail/move-to-menu-items"
|
||
import { MAIL_MENU_SURFACE_CLASS } from "@/lib/mail-chrome-classes"
|
||
import type { MailXsViewChrome } from "@/lib/mail-xs-view-chrome"
|
||
import { cn } from "@/lib/utils"
|
||
|
||
interface MobileBottomBarProps {
|
||
sidebarOpen: boolean
|
||
onToggleSidebar: () => void
|
||
/** Lecture message xs : barre d’actions à la place du menu / recherche. */
|
||
xsViewChrome?: MailXsViewChrome | null
|
||
}
|
||
|
||
const ROUNDED_BAR_BTN =
|
||
"size-11 shrink-0 rounded-full border border-gray-200 bg-white/80 text-[#444746] shadow-md backdrop-blur hover:bg-white"
|
||
|
||
export function MobileBottomBar({
|
||
sidebarOpen,
|
||
onToggleSidebar,
|
||
xsViewChrome = null,
|
||
}: MobileBottomBarProps) {
|
||
const [searchValue, setSearchValue] = useState("")
|
||
const inputRef = useRef<HTMLInputElement>(null)
|
||
const { openCompose } = useComposeActions()
|
||
const inMailView = Boolean(xsViewChrome)
|
||
|
||
const hasSearch = searchValue.length > 0
|
||
|
||
const handleClear = useCallback(() => {
|
||
setSearchValue("")
|
||
inputRef.current?.focus()
|
||
}, [])
|
||
|
||
useEffect(() => {
|
||
if (sidebarOpen) {
|
||
inputRef.current?.blur()
|
||
}
|
||
}, [sidebarOpen])
|
||
|
||
return (
|
||
<div className="fixed inset-x-0 bottom-0 z-50 flex flex-col items-center pb-[env(safe-area-inset-bottom)] sm:hidden">
|
||
<div className={cn(
|
||
"pointer-events-none absolute inset-0 bg-gradient-to-t to-transparent",
|
||
inMailView
|
||
? "from-black/90 via-black/50"
|
||
: "from-mail-surface/95 via-mail-surface/70 dark:from-background/95 dark:via-background/70"
|
||
)} />
|
||
|
||
<div className="relative z-10 flex w-full items-center gap-2 px-3 pb-3 pt-2">
|
||
{inMailView && xsViewChrome ? (
|
||
<div className="flex shrink-0 overflow-hidden rounded-full border border-gray-200 bg-white/80 shadow-md backdrop-blur">
|
||
<Button
|
||
type="button"
|
||
variant="ghost"
|
||
size="icon"
|
||
className="size-11 rounded-none text-[#444746] hover:bg-[#f1f3f4]"
|
||
onClick={xsViewChrome.onArchive}
|
||
aria-label="Archiver"
|
||
>
|
||
<Archive className="size-5" strokeWidth={1.5} />
|
||
</Button>
|
||
<span className="w-px shrink-0 self-stretch bg-gray-200" aria-hidden />
|
||
<DropdownMenu>
|
||
<DropdownMenuTrigger asChild>
|
||
<Button
|
||
type="button"
|
||
variant="ghost"
|
||
size="icon"
|
||
className="size-11 rounded-none text-[#444746] hover:bg-[#f1f3f4]"
|
||
aria-label="Déplacer dans un dossier"
|
||
>
|
||
<FolderInput className="size-5" strokeWidth={1.5} />
|
||
</Button>
|
||
</DropdownMenuTrigger>
|
||
<DropdownMenuContent
|
||
align="start"
|
||
side="top"
|
||
sideOffset={8}
|
||
className={cn(MAIL_MENU_SURFACE_CLASS, "max-h-80 overflow-y-auto")}
|
||
>
|
||
<MoveToDropdownItems
|
||
targets={xsViewChrome.moveTargets}
|
||
onMoveTo={xsViewChrome.onMoveTo}
|
||
/>
|
||
</DropdownMenuContent>
|
||
</DropdownMenu>
|
||
<span className="w-px shrink-0 self-stretch bg-gray-200" aria-hidden />
|
||
<Button
|
||
type="button"
|
||
variant="ghost"
|
||
size="icon"
|
||
className="size-11 rounded-none text-[#444746] hover:bg-[#f1f3f4]"
|
||
onClick={xsViewChrome.onReply}
|
||
aria-label="Répondre"
|
||
>
|
||
<Reply className="size-5" strokeWidth={1.5} />
|
||
</Button>
|
||
</div>
|
||
) : (
|
||
<>
|
||
<Button
|
||
variant="ghost"
|
||
size="icon"
|
||
className={ROUNDED_BAR_BTN}
|
||
onClick={onToggleSidebar}
|
||
aria-label={sidebarOpen ? "Fermer le menu" : "Ouvrir le menu"}
|
||
>
|
||
{sidebarOpen ? (
|
||
<X className="size-5" />
|
||
) : (
|
||
<Menu className="size-5" />
|
||
)}
|
||
</Button>
|
||
|
||
{!sidebarOpen && (
|
||
<div className="relative flex min-w-0 flex-1 items-center">
|
||
<div className="pointer-events-none absolute left-3 z-10 flex items-center text-gray-500">
|
||
<Search className="size-5" />
|
||
</div>
|
||
<input
|
||
ref={inputRef}
|
||
type="text"
|
||
value={searchValue}
|
||
onChange={(e) => setSearchValue(e.target.value)}
|
||
placeholder="Rechercher"
|
||
className="h-11 w-full rounded-full border border-gray-200 bg-white/80 pl-10 pr-4 text-sm shadow-md backdrop-blur outline-none placeholder:text-gray-400 focus:ring-2 focus:ring-blue-500/40"
|
||
/>
|
||
</div>
|
||
)}
|
||
</>
|
||
)}
|
||
|
||
{!sidebarOpen && (
|
||
<Button
|
||
variant="ghost"
|
||
size="icon"
|
||
className={cn(ROUNDED_BAR_BTN, inMailView && "ml-auto")}
|
||
onClick={inMailView || !hasSearch ? openCompose : handleClear}
|
||
aria-label={!inMailView && hasSearch ? "Effacer la recherche" : "Nouveau message"}
|
||
>
|
||
{!inMailView && hasSearch ? (
|
||
<X className="size-5" />
|
||
) : (
|
||
<Pencil className="size-5" />
|
||
)}
|
||
</Button>
|
||
)}
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|