ultisuite-client/components/drive/richtext/docs-view-menu.tsx
R3D347HR4Y 2a7c153748
Some checks are pending
E2E / Playwright e2e (push) Waiting to run
wrap page
2026-06-10 12:48:27 +02:00

292 lines
8.4 KiB
TypeScript

"use client"
import type { ReactNode } from "react"
import {
AlignHorizontalSpaceAround,
Check,
Eye,
ListTree,
Maximize2,
MessageSquare,
MessageSquarePlus,
Pencil,
} from "lucide-react"
import {
MenubarCheckboxItem,
MenubarContent,
MenubarItem,
MenubarMenu,
MenubarSeparator,
MenubarSubContent,
MenubarSubTrigger,
MenubarTrigger,
} from "@/components/ui/menubar"
import {
DocsExclusiveMenuSub,
DocsExclusiveMenuSubRoot,
} from "@/components/drive/richtext/docs-exclusive-menu-sub"
import { DocsMenuShortcut } from "@/components/drive/richtext/docs-menu-shortcut"
import { DOCS_MENUBAR_CONTENT_PROPS } from "@/components/drive/richtext/docs-menubar-props"
import type {
DocsCommentsDisplay,
DocsEditorMode,
} from "@/lib/drive/docs-view-settings"
import { cn } from "@/lib/utils"
export type DocsViewMenuState = {
editorMode: DocsEditorMode
commentsDisplay: DocsCommentsDisplay
showLayout: boolean
showRuler: boolean
showEquationToolbar: boolean
showNonPrintableChars: boolean
}
export type DocsViewMenuActions = {
onEditorModeChange: (mode: DocsEditorMode) => void
onCommentsDisplayChange: (display: DocsCommentsDisplay) => void
onToggleOutlineSidebar: () => void
onToggleShowLayout: () => void
onToggleShowRuler: () => void
onToggleShowEquationToolbar: () => void
onToggleShowNonPrintableChars: () => void
onFullscreen: () => void
}
const EDITOR_MODES = [
{
id: "edit" as const,
label: "Édition",
description: "Modifier le document directement",
icon: Pencil,
},
{
id: "suggest" as const,
label: "Suggestion",
description: "Suggérer des modifications",
icon: MessageSquarePlus,
},
{
id: "view" as const,
label: "Affichage",
description: "Lire ou imprimer le document final",
icon: Eye,
},
] as const
const COMMENTS_OPTIONS = [
{ id: "hidden" as const, label: "Masquer les commentaires" },
{ id: "collapsed" as const, label: "Réduire les commentaires" },
{ id: "expanded" as const, label: "Développer les commentaires" },
{ id: "all" as const, label: "Afficher tous les commentaires" },
] as const
function MenuIcon({ children }: { children: ReactNode }) {
return <span className="docs-menu-item-icon">{children}</span>
}
function CheckMenuOption({
checked,
onSelect,
children,
disabled,
}: {
checked: boolean
onSelect: () => void
children: ReactNode
disabled?: boolean
}) {
return (
<MenubarItem
className="docs-menu-item relative pl-8"
disabled={disabled}
onClick={onSelect}
>
{checked ? <Check className="absolute left-2 size-4" aria-hidden /> : null}
{children}
</MenubarItem>
)
}
function ModeMenuOption({
icon: Icon,
label,
description,
selected,
onSelect,
disabled,
}: {
icon: typeof Pencil
label: string
description: string
selected: boolean
onSelect: () => void
disabled?: boolean
}) {
return (
<MenubarItem
className={cn("docs-menu-item docs-menu-mode-item items-start py-2", selected && "bg-accent/60")}
disabled={disabled}
onClick={onSelect}
>
<MenuIcon>
<Icon className="size-4" />
</MenuIcon>
<span className="flex min-w-0 flex-col gap-0.5 leading-tight">
<span className="text-sm font-normal">{label}</span>
<span className="text-xs text-[#5f6368] dark:text-muted-foreground">{description}</span>
</span>
</MenubarItem>
)
}
export function DocsViewMenu({
state,
actions,
disabled,
}: {
state: DocsViewMenuState
actions: DocsViewMenuActions
disabled?: boolean
}) {
return (
<MenubarMenu>
<MenubarTrigger className="docs-menu-trigger">Affichage</MenubarTrigger>
<MenubarContent
{...DOCS_MENUBAR_CONTENT_PROPS}
className="docs-menu-content min-w-[300px] overflow-visible"
data-docs-menu-surface
>
<DocsExclusiveMenuSubRoot>
<DocsExclusiveMenuSub id="mode">
<MenubarSubTrigger className="docs-menu-item" disabled={disabled}>
<MenuIcon>
<Pencil className="size-4" />
</MenuIcon>
Mode
</MenubarSubTrigger>
<MenubarSubContent
className="docs-menu-content docs-menu-sub-content min-w-[280px] overflow-visible"
data-docs-menu-surface
>
{EDITOR_MODES.map((mode) => (
<ModeMenuOption
key={mode.id}
icon={mode.icon}
label={mode.label}
description={mode.description}
selected={state.editorMode === mode.id}
disabled={disabled}
onSelect={() => actions.onEditorModeChange(mode.id)}
/>
))}
</MenubarSubContent>
</DocsExclusiveMenuSub>
<DocsExclusiveMenuSub id="comments">
<MenubarSubTrigger className="docs-menu-item" disabled={disabled}>
<MenuIcon>
<MessageSquare className="size-4" />
</MenuIcon>
Commentaires
</MenubarSubTrigger>
<MenubarSubContent
className="docs-menu-content docs-menu-sub-content min-w-[260px] overflow-visible"
data-docs-menu-surface
>
{COMMENTS_OPTIONS.map((option) => (
<CheckMenuOption
key={option.id}
checked={state.commentsDisplay === option.id}
disabled={disabled}
onSelect={() => actions.onCommentsDisplayChange(option.id)}
>
{option.label}
</CheckMenuOption>
))}
</MenubarSubContent>
</DocsExclusiveMenuSub>
<MenubarItem
className="docs-menu-item"
disabled={disabled}
onClick={actions.onToggleOutlineSidebar}
>
<MenuIcon>
<ListTree className="size-4" />
</MenuIcon>
Développer la barre latérale des onglets et sections
<span className="docs-menu-shortcut-sequence ml-auto text-xs text-[#5f6368] dark:text-muted-foreground">
Ctrl+A Ctrl+H
</span>
</MenubarItem>
<MenubarSeparator />
<DocsExclusiveMenuSub id="text-width">
<MenubarSubTrigger className="docs-menu-item" disabled>
<MenuIcon>
<AlignHorizontalSpaceAround className="size-4" />
</MenuIcon>
Largeur du texte
</MenubarSubTrigger>
<MenubarSubContent
className="docs-menu-content docs-menu-sub-content min-w-[220px] overflow-visible"
data-docs-menu-surface
>
<MenubarItem disabled className="docs-menu-item text-muted-foreground">
Bientôt disponible
</MenubarItem>
</MenubarSubContent>
</DocsExclusiveMenuSub>
<MenubarSeparator />
</DocsExclusiveMenuSubRoot>
<MenubarCheckboxItem
className="docs-menu-item docs-menu-checkbox-item"
checked={state.showLayout}
disabled={disabled}
onCheckedChange={() => actions.onToggleShowLayout()}
>
Afficher la mise en page
</MenubarCheckboxItem>
<MenubarCheckboxItem
className="docs-menu-item docs-menu-checkbox-item"
checked={state.showRuler}
disabled={disabled}
onCheckedChange={() => actions.onToggleShowRuler()}
>
Afficher la règle
</MenubarCheckboxItem>
<MenubarCheckboxItem
className="docs-menu-item docs-menu-checkbox-item"
checked={state.showEquationToolbar}
disabled={disabled}
onCheckedChange={() => actions.onToggleShowEquationToolbar()}
>
Afficher la barre d&apos;outils d&apos;équation
</MenubarCheckboxItem>
<MenubarCheckboxItem
className="docs-menu-item docs-menu-checkbox-item"
checked={state.showNonPrintableChars}
disabled={disabled}
onCheckedChange={() => actions.onToggleShowNonPrintableChars()}
>
Afficher les caractères non imprimables
<DocsMenuShortcut shortcutId="view.showNonPrintable" />
</MenubarCheckboxItem>
<MenubarSeparator />
<MenubarItem className="docs-menu-item" disabled={disabled} onClick={actions.onFullscreen}>
<MenuIcon>
<Maximize2 className="size-4" />
</MenuIcon>
Plein écran
</MenubarItem>
</MenubarContent>
</MenubarMenu>
)
}