ultisuite-client/components/drive/drive-mobile-bottom-bar.tsx
R3D347HR4Y ad1370ea7e
Some checks are pending
E2E / Playwright e2e (push) Waiting to run
feat: enhance configuration and add new demo layouts
- Introduced turbopack alias for canvas in next.config.mjs.
- Updated package.json scripts for development and branding tasks.
- Added new dependencies for Tiptap extensions.
- Implemented new demo layouts for agenda, contacts, drive, and mail applications.
- Enhanced globals.css for improved theming and splash screen animations.
- Added OAuth callback handling for drive mounts.
- Updated layout components to integrate new demo shells and improve structure.
2026-06-12 19:10:24 +02:00

154 lines
5.0 KiB
TypeScript

"use client"
import { useState } from "react"
import { useRouter } from "next/navigation"
import { Menu, Plus, Search, X } from "lucide-react"
import { Button } from "@/components/ui/button"
import { DriveMobileSearchSheet } from "@/components/drive/drive-mobile-search-sheet"
import { DriveNewSheet } from "@/components/drive/drive-new-sheet"
import type { DriveFileInfo } from "@/lib/api/types"
import { openDriveItem } from "@/lib/drive/drive-open-item"
import {
type DriveSearchScope,
buildDriveSearchUrl,
defaultDriveSearchScope,
fileBrowserViewForSearchScope,
} from "@/lib/drive/drive-search"
import { useDriveRouteRoot } from "@/lib/drive/drive-route-context"
import type { DriveView } from "@/lib/drive/drive-url"
import { useDriveUIStore } from "@/lib/stores/drive-ui-store"
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 DriveMobileBottomBar({
search,
onSearchChange,
searchScope,
onSearchScopeChange,
folderPath,
contextView,
resultsMode = false,
parentPath,
}: {
search: string
onSearchChange: (q: string) => void
searchScope: DriveSearchScope
onSearchScopeChange: (scope: DriveSearchScope) => void
folderPath: string
contextView: DriveView
resultsMode?: boolean
parentPath: string
}) {
const router = useRouter()
const routeRoot = useDriveRouteRoot()
const openPreview = useDriveUIStore((s) => s.openPreview)
const sidebarCollapsed = useDriveUIStore((s) => s.sidebarCollapsed)
const setSidebarCollapsed = useDriveUIStore((s) => s.setSidebarCollapsed)
const sidebarOpen = !sidebarCollapsed
const [searchOpen, setSearchOpen] = useState(false)
const [newOpen, setNewOpen] = useState(false)
const toggleSidebar = () => setSidebarCollapsed(!sidebarCollapsed)
const effectiveScope =
searchScope === "folder" && folderPath === "/"
? defaultDriveSearchScope(contextView, folderPath)
: searchScope
const submitSearch = () => {
const q = search.trim()
if (!q) return
router.push(
buildDriveSearchUrl(
{
query: q,
scope: effectiveScope,
folderPath: effectiveScope === "folder" ? folderPath : "/",
},
routeRoot
)
)
}
const openSuggestion = (item: DriveFileInfo, contextItems: DriveFileInfo[]) => {
openDriveItem(item, {
router,
openPreview,
view: fileBrowserViewForSearchScope(effectiveScope),
contextItems,
})
}
return (
<>
<DriveMobileSearchSheet
open={searchOpen}
onClose={() => setSearchOpen(false)}
search={search}
onSearchChange={onSearchChange}
searchScope={searchScope}
onSearchScopeChange={onSearchScopeChange}
folderPath={folderPath}
contextView={contextView}
resultsMode={resultsMode}
onPickItem={openSuggestion}
onSubmitSearch={submitSearch}
/>
<DriveNewSheet parentPath={parentPath} open={newOpen} onOpenChange={setNewOpen} />
<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="pointer-events-none absolute inset-0 bg-gradient-to-t from-app-canvas/95 via-app-canvas/70 to-transparent" />
<div className="relative z-10 flex w-full items-center gap-2 px-3 pb-3 pt-2">
<Button
type="button"
variant="ghost"
size="icon"
className={ROUNDED_BAR_BTN}
onClick={toggleSidebar}
aria-label={sidebarOpen ? "Fermer le menu" : "Ouvrir le menu"}
>
{sidebarOpen ? <X className="size-5" /> : <Menu className="size-5" />}
</Button>
{!sidebarOpen && (
<>
<button
type="button"
className="relative flex min-w-0 flex-1 items-center"
onClick={() => setSearchOpen(true)}
>
<div className="pointer-events-none absolute left-3 z-10 flex items-center text-gray-500">
<Search className="size-5" />
</div>
<div className="flex h-11 w-full items-center rounded-full border border-gray-200 bg-white/80 pl-10 pr-4 text-left text-sm shadow-md backdrop-blur">
<span
className={
search
? "truncate text-gray-900 dark:text-gray-100"
: "text-gray-400"
}
>
{search || "Rechercher dans Drive"}
</span>
</div>
</button>
<Button
type="button"
variant="ghost"
size="icon"
className={ROUNDED_BAR_BTN}
onClick={() => setNewOpen(true)}
aria-label="Nouveau"
>
<Plus className="size-5" />
</Button>
</>
)}
</div>
</div>
</>
)
}