186 lines
6.3 KiB
TypeScript
186 lines
6.3 KiB
TypeScript
"use client"
|
|
|
|
import type { ReactNode } from "react"
|
|
import Link from "next/link"
|
|
import { Globe, Lock, Star, Users } from "lucide-react"
|
|
import { EditorAccountButton } from "@/components/drive/editor-account-button"
|
|
import { OfficeEditorInlineTitle } from "@/components/drive/office-editor-inline-title"
|
|
import { ShareDialog } from "@/components/drive/share-dialog"
|
|
import { CollabPresenceAvatars } from "@/components/drive/richtext/collab-presence-avatars"
|
|
import { DocsLogoIcon } from "@/components/drive/richtext/docs-logo-icon"
|
|
import { DocsMenubar } from "@/components/drive/richtext/docs-menubar"
|
|
import { DocsMoveButton } from "@/components/drive/richtext/docs-move-button"
|
|
import { Button } from "@/components/ui/button"
|
|
import type { DriveShare, DriveFileInfo } from "@/lib/api/types"
|
|
import type { CollabPresenceUser } from "@/lib/drive/use-collab-presence"
|
|
import {
|
|
resolveShareButtonIcon,
|
|
type ShareButtonIcon,
|
|
} from "@/lib/drive/drive-share-button-state"
|
|
import type { PageFormatId } from "@/lib/drive/page-formats"
|
|
import type { RichTextSaveStatus } from "@/lib/drive/richtext-types"
|
|
import { cn } from "@/lib/utils"
|
|
|
|
function ShareButtonIcon({ kind }: { kind: ShareButtonIcon }) {
|
|
if (kind === "globe") return <Globe className="h-4 w-4" aria-hidden />
|
|
if (kind === "users") return <Users className="h-4 w-4" aria-hidden />
|
|
return <Lock className="h-4 w-4" aria-hidden />
|
|
}
|
|
|
|
function saveStatusLabel(status: RichTextSaveStatus): string {
|
|
switch (status) {
|
|
case "saving":
|
|
return "Enregistrement…"
|
|
case "saved":
|
|
return "Enregistré dans UltiDrive"
|
|
case "error":
|
|
return "Erreur d'enregistrement"
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
export function DocsChrome({
|
|
title,
|
|
onRename,
|
|
renameDisabled,
|
|
backHref,
|
|
backLabel,
|
|
showBack = true,
|
|
shares = [],
|
|
onShareClick,
|
|
showShare = false,
|
|
showAccount = false,
|
|
saveStatus = "idle",
|
|
presenceUsers = [],
|
|
pageFormatId,
|
|
onPageFormatChange,
|
|
zoom,
|
|
onZoomChange,
|
|
trailing,
|
|
moveFile,
|
|
onFileMoved,
|
|
}: {
|
|
title: string
|
|
onRename?: (next: string) => Promise<void>
|
|
renameDisabled?: boolean
|
|
backHref?: string
|
|
backLabel?: string
|
|
showBack?: boolean
|
|
shares?: DriveShare[]
|
|
onShareClick?: () => void
|
|
showShare?: boolean
|
|
showAccount?: boolean
|
|
saveStatus?: RichTextSaveStatus
|
|
presenceUsers?: CollabPresenceUser[]
|
|
pageFormatId: PageFormatId
|
|
onPageFormatChange: (id: PageFormatId) => void
|
|
zoom: number
|
|
onZoomChange: (zoom: number) => void
|
|
trailing?: ReactNode
|
|
/** Propriétaire uniquement — affiche le bouton déplacer. */
|
|
moveFile?: DriveFileInfo
|
|
onFileMoved?: (newPath: string) => void
|
|
}) {
|
|
const shareIcon = resolveShareButtonIcon(shares)
|
|
const statusText = saveStatusLabel(saveStatus)
|
|
const iconHref = showBack !== false && backHref ? backHref : "/drive"
|
|
const iconLabel =
|
|
showBack !== false && backHref
|
|
? (backLabel ?? "Retour au Drive")
|
|
: "Ouvrir le Drive"
|
|
|
|
return (
|
|
<>
|
|
<header className="shrink-0 bg-white dark:bg-background">
|
|
<div className="flex min-h-[72px] items-center gap-0 px-2 py-1">
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
className="mr-1 size-11 shrink-0 self-center rounded-full hover:bg-[#e8eaed] dark:hover:bg-muted"
|
|
asChild
|
|
>
|
|
<Link href={iconHref} aria-label={iconLabel}>
|
|
<DocsLogoIcon className="size-[38px]" />
|
|
</Link>
|
|
</Button>
|
|
|
|
<div className="min-w-0 flex-1 self-center">
|
|
<div className="docs-chrome-title-row flex min-w-0 items-center gap-0 leading-tight">
|
|
{onRename ? (
|
|
<OfficeEditorInlineTitle
|
|
value={title}
|
|
onRename={onRename}
|
|
disabled={renameDisabled}
|
|
className="pr-1 text-base font-normal"
|
|
/>
|
|
) : (
|
|
<span className="block truncate pl-2 pr-1 text-base font-normal">{title}</span>
|
|
)}
|
|
<div className="flex shrink-0 items-center -space-x-0.5">
|
|
<Button
|
|
type="button"
|
|
variant="ghost"
|
|
size="icon"
|
|
className="size-7 shrink-0 text-muted-foreground"
|
|
disabled
|
|
aria-label="Ajouter aux favoris (bientôt)"
|
|
>
|
|
<Star className="size-4" />
|
|
</Button>
|
|
{moveFile && onFileMoved ? (
|
|
<DocsMoveButton file={moveFile} onFileMoved={onFileMoved} />
|
|
) : null}
|
|
</div>
|
|
{statusText ? (
|
|
<span
|
|
className={cn(
|
|
"ml-1.5 hidden min-w-0 line-clamp-1 overflow-hidden break-all text-ellipsis text-xs text-[#5f6368] sm:inline dark:text-muted-foreground",
|
|
saveStatus === "error" && "text-destructive"
|
|
)}
|
|
>
|
|
{statusText}
|
|
</span>
|
|
) : null}
|
|
</div>
|
|
|
|
<div className="-mt-1 flex min-w-0 items-center overflow-hidden">
|
|
<DocsMenubar
|
|
className="docs-menubar shrink-0"
|
|
pageFormatId={pageFormatId}
|
|
onPageFormatChange={onPageFormatChange}
|
|
zoom={zoom}
|
|
onZoomChange={onZoomChange}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex shrink-0 items-center gap-2 self-center pl-2">
|
|
{trailing}
|
|
{presenceUsers.length > 0 ? (
|
|
<CollabPresenceAvatars users={presenceUsers} />
|
|
) : null}
|
|
{showShare ? (
|
|
<Button
|
|
type="button"
|
|
size="sm"
|
|
className={cn(
|
|
"gap-2 rounded-full border-0 px-5 shadow-none",
|
|
"bg-[#1967d2] text-white hover:bg-[#185abc] hover:text-white",
|
|
"dark:bg-[#e8eaed] dark:text-[#3c4043] dark:hover:bg-[#dadce0] dark:hover:text-[#202124]"
|
|
)}
|
|
onClick={onShareClick}
|
|
>
|
|
<ShareButtonIcon kind={shareIcon} />
|
|
Partager
|
|
</Button>
|
|
) : null}
|
|
{showAccount ? <EditorAccountButton /> : null}
|
|
</div>
|
|
</div>
|
|
</header>
|
|
{showShare ? <ShareDialog /> : null}
|
|
</>
|
|
)
|
|
}
|