ultisuite-client/components/drive/richtext/docs-insert-menu.tsx
R3D347HR4Y 303b2b1074
Some checks are pending
E2E / Playwright e2e (push) Waiting to run
wow
2026-06-11 01:22:40 +02:00

584 lines
22 KiB
TypeScript

"use client"
import type { ReactNode } from "react"
import { Icon } from "@iconify/react"
import {
BarChart3,
Bookmark,
Calendar,
CircleDot,
FileText,
ImageIcon,
Link2,
MessageSquarePlus,
Minus,
PenLine,
Plus,
Shapes,
Smile,
Table2,
Upload,
} from "lucide-react"
import { DocsExclusiveMenuSub, DocsExclusiveMenuSubRoot } from "@/components/drive/richtext/docs-exclusive-menu-sub"
import { DocsInsertTablePicker } from "@/components/drive/richtext/docs-insert-table-picker"
import { DOCS_MENUBAR_CONTENT_PROPS } from "@/components/drive/richtext/docs-menubar-props"
import {
MenubarContent,
MenubarItem,
MenubarMenu,
MenubarSeparator,
MenubarShortcut,
MenubarSubContent,
MenubarSubTrigger,
MenubarTrigger,
} from "@/components/ui/menubar"
import { suitePublicAsset } from "@/lib/suite/suite-public-asset"
export type DocsInsertMenuActions = {
onInsertImageFromComputer: () => void
onInsertImageFromDrive: () => void
onInsertNewDraw: () => void
onInsertDrawFromDrive: () => void
onInsertLink: () => void
onInsertHorizontalRule: () => void
onInsertTable: (rows: number, cols: number) => void
onInsertHeader: () => void
onInsertFooter: () => void
onInsertWatermark: () => void
onInsertPageNumbersHeader: () => void
onInsertPageNumbersFooter: () => void
onOpenPageNumbersOptions: () => void
}
function MenuIcon({ children }: { children: ReactNode }) {
return <span className="docs-menu-item-icon">{children}</span>
}
function DocsMenuBadge({ children }: { children: ReactNode }) {
return (
<span className="docs-menu-badge ml-auto shrink-0 rounded px-1.5 py-px text-[10px] font-medium leading-tight text-white">
{children}
</span>
)
}
function DisabledMenuItem({
icon,
children,
badge,
shortcut,
}: {
icon: ReactNode
children: ReactNode
badge?: ReactNode
shortcut?: string
}) {
return (
<MenubarItem className="docs-menu-item" disabled>
<MenuIcon>{icon}</MenuIcon>
{children}
{badge}
{shortcut ? <MenubarShortcut>{shortcut}</MenubarShortcut> : null}
</MenubarItem>
)
}
function InsertBuildingBlockItems() {
return (
<>
<DisabledMenuItem icon={<Calendar className="size-4" />}>Notes de réunion</DisabledMenuItem>
<DisabledMenuItem icon={<Icon icon="material-symbols:mail-outline" className="size-4" />}>
Brouillon d&apos;email
</DisabledMenuItem>
<DisabledMenuItem icon={<Icon icon="material-symbols:format-list-bulleted" className="size-4" />}>
Journal simple des décisions
</DisabledMenuItem>
<MenubarSeparator />
<DisabledMenuItem icon={<Icon icon="material-symbols:more-vert" className="size-4" />}>
Voir plus
</DisabledMenuItem>
</>
)
}
function InsertPlaceholderChipItems() {
return (
<>
<DisabledMenuItem icon={<Calendar className="size-4" />}>Date</DisabledMenuItem>
<DisabledMenuItem icon={<Icon icon="material-symbols:person-outline" className="size-4" />}>
Personne
</DisabledMenuItem>
<DisabledMenuItem icon={<FileText className="size-4" />}>Fichier</DisabledMenuItem>
<DisabledMenuItem icon={<Icon icon="material-symbols:event-outline" className="size-4" />}>
Événement d&apos;agenda
</DisabledMenuItem>
<DisabledMenuItem icon={<Icon icon="material-symbols:location-on-outline" className="size-4" />}>
Lieu
</DisabledMenuItem>
</>
)
}
export function DocsInsertMenu({
actions,
disabled,
pageElementsEnabled = true,
}: {
actions: DocsInsertMenuActions
disabled?: boolean
pageElementsEnabled?: boolean
}) {
const pageElementsDisabled = disabled || !pageElementsEnabled
return (
<MenubarMenu>
<MenubarTrigger className="docs-menu-trigger">Insertion</MenubarTrigger>
<MenubarContent
{...DOCS_MENUBAR_CONTENT_PROPS}
className="docs-menu-content min-w-[300px] overflow-visible"
data-docs-menu-surface
>
<DocsExclusiveMenuSubRoot>
<DocsExclusiveMenuSub id="insert-image">
<MenubarSubTrigger className="docs-menu-item" disabled={disabled}>
<MenuIcon>
<ImageIcon className="size-4" />
</MenuIcon>
Image
</MenubarSubTrigger>
<MenubarSubContent
className="docs-menu-content docs-menu-sub-content min-w-[260px] overflow-visible"
data-docs-menu-surface
>
<MenubarItem
className="docs-menu-item"
disabled={disabled}
onClick={actions.onInsertImageFromComputer}
>
<MenuIcon>
<Upload className="size-4" />
</MenuIcon>
Importer depuis l&apos;ordinateur
</MenubarItem>
<DisabledMenuItem icon={<Icon icon="material-symbols:search" className="size-4" />}>
Rechercher sur le Web
</DisabledMenuItem>
<MenubarSeparator />
<MenubarItem
className="docs-menu-item"
disabled={disabled}
onClick={actions.onInsertImageFromDrive}
>
<MenuIcon>
<img
src={suitePublicAsset("/ultidrive-mark.svg")}
alt=""
className="size-4"
aria-hidden
/>
</MenuIcon>
Drive
</MenubarItem>
<DisabledMenuItem icon={<Icon icon="logos:google-photos" className="size-4" />}>
Photos
</DisabledMenuItem>
<DisabledMenuItem icon={<Icon icon="material-symbols:photo-camera-outline" className="size-4" />}>
Appareil photo
</DisabledMenuItem>
<DisabledMenuItem icon={<Link2 className="size-4" />}>
À partir d&apos;une URL
</DisabledMenuItem>
</MenubarSubContent>
</DocsExclusiveMenuSub>
<DocsExclusiveMenuSub id="insert-table">
<MenubarSubTrigger className="docs-menu-item" disabled={disabled}>
<MenuIcon>
<Table2 className="size-4" />
</MenuIcon>
Tableau
</MenubarSubTrigger>
<MenubarSubContent
className="docs-menu-content docs-menu-sub-content min-w-[220px] overflow-visible p-0"
data-docs-menu-surface
>
<DocsExclusiveMenuSub id="insert-table-building-blocks">
<MenubarSubTrigger className="docs-menu-item" disabled>
<MenuIcon>
<FileText className="size-4" />
</MenuIcon>
Composants de base
</MenubarSubTrigger>
<MenubarSubContent
className="docs-menu-content docs-menu-sub-content min-w-[260px] overflow-visible"
data-docs-menu-surface
>
<InsertBuildingBlockItems />
</MenubarSubContent>
</DocsExclusiveMenuSub>
<DocsInsertTablePicker
onInsert={(rows, cols) => {
if (disabled) return
actions.onInsertTable(rows, cols)
}}
/>
</MenubarSubContent>
</DocsExclusiveMenuSub>
<DocsExclusiveMenuSub id="insert-building-blocks">
<MenubarSubTrigger className="docs-menu-item">
<MenuIcon>
<Plus className="size-4" />
</MenuIcon>
Composants de base
</MenubarSubTrigger>
<MenubarSubContent
className="docs-menu-content docs-menu-sub-content min-w-[260px] overflow-visible"
data-docs-menu-surface
>
<InsertBuildingBlockItems />
</MenubarSubContent>
</DocsExclusiveMenuSub>
<DocsExclusiveMenuSub id="insert-smart-chips">
<MenubarSubTrigger className="docs-menu-item">
<MenuIcon>
<CircleDot className="size-4" />
</MenuIcon>
Chips intelligents
</MenubarSubTrigger>
<MenubarSubContent
className="docs-menu-content docs-menu-sub-content min-w-[260px] overflow-visible"
data-docs-menu-surface
>
<DisabledMenuItem icon={<Calendar className="size-4" />}>Date</DisabledMenuItem>
<DisabledMenuItem icon={<Icon icon="material-symbols:person-outline" className="size-4" />}>
Contact
</DisabledMenuItem>
<DisabledMenuItem icon={<FileText className="size-4" />}>Fichier</DisabledMenuItem>
<DisabledMenuItem icon={<Icon icon="material-symbols:event-outline" className="size-4" />}>
Événement d&apos;agenda
</DisabledMenuItem>
<DisabledMenuItem icon={<Icon icon="material-symbols:location-on-outline" className="size-4" />}>
Lieu
</DisabledMenuItem>
<DocsExclusiveMenuSub id="insert-placeholder-chips">
<MenubarSubTrigger className="docs-menu-item" disabled>
<MenuIcon>
<CircleDot className="size-4" />
</MenuIcon>
Chips d&apos;espace réservé
</MenubarSubTrigger>
<MenubarSubContent
className="docs-menu-content docs-menu-sub-content min-w-[240px] overflow-visible"
data-docs-menu-surface
>
<InsertPlaceholderChipItems />
</MenubarSubContent>
</DocsExclusiveMenuSub>
<DisabledMenuItem icon={<Icon icon="material-symbols:arrow-drop-down-circle-outline" className="size-4" />}>
Menu déroulant
</DisabledMenuItem>
</MenubarSubContent>
</DocsExclusiveMenuSub>
<DocsExclusiveMenuSub id="insert-esignatures">
<MenubarSubTrigger className="docs-menu-item" disabled>
<MenuIcon>
<PenLine className="size-4" />
</MenuIcon>
Signatures électroniques
<DocsMenuBadge>Premium</DocsMenuBadge>
</MenubarSubTrigger>
<MenubarSubContent
className="docs-menu-content docs-menu-sub-content min-w-[260px] overflow-visible"
data-docs-menu-surface
>
<DisabledMenuItem icon={<PenLine className="size-4" />}>
Insérer un champ de signature
</DisabledMenuItem>
<DisabledMenuItem icon={<Icon icon="material-symbols:draw-outline" className="size-4" />}>
Demander une signature
</DisabledMenuItem>
</MenubarSubContent>
</DocsExclusiveMenuSub>
<MenubarItem className="docs-menu-item" disabled={disabled} onClick={actions.onInsertLink}>
<MenuIcon>
<Link2 className="size-4" />
</MenuIcon>
Lien
<MenubarShortcut>K</MenubarShortcut>
</MenubarItem>
<DocsExclusiveMenuSub id="insert-draw">
<MenubarSubTrigger className="docs-menu-item" disabled={disabled}>
<MenuIcon>
<Shapes className="size-4" />
</MenuIcon>
Dessin
</MenubarSubTrigger>
<MenubarSubContent
className="docs-menu-content docs-menu-sub-content min-w-[220px] overflow-visible"
data-docs-menu-surface
>
<MenubarItem
className="docs-menu-item"
disabled={disabled}
onClick={actions.onInsertNewDraw}
>
<MenuIcon>
<Plus className="size-4" />
</MenuIcon>
Nouveau
</MenubarItem>
<MenubarItem
className="docs-menu-item"
disabled={disabled}
onClick={actions.onInsertDrawFromDrive}
>
<MenuIcon>
<img
src={suitePublicAsset("/ultidrive-mark.svg")}
alt=""
className="size-4"
aria-hidden
/>
</MenuIcon>
À partir de Drive
</MenubarItem>
</MenubarSubContent>
</DocsExclusiveMenuSub>
<DocsExclusiveMenuSub id="insert-chart">
<MenubarSubTrigger className="docs-menu-item">
<MenuIcon>
<BarChart3 className="size-4" />
</MenuIcon>
Graphique
</MenubarSubTrigger>
<MenubarSubContent
className="docs-menu-content docs-menu-sub-content min-w-[200px] overflow-visible"
data-docs-menu-surface
>
<DisabledMenuItem icon={<Icon icon="material-symbols:bar-chart" className="size-4" />}>
Barres
</DisabledMenuItem>
<DisabledMenuItem icon={<Icon icon="material-symbols:insert-chart-outline" className="size-4" />}>
Colonnes
</DisabledMenuItem>
<DisabledMenuItem icon={<Icon icon="material-symbols:show-chart" className="size-4" />}>
Lignes
</DisabledMenuItem>
<DisabledMenuItem icon={<Icon icon="material-symbols:pie-chart-outline" className="size-4" />}>
Secteurs
</DisabledMenuItem>
<MenubarSeparator />
<DisabledMenuItem icon={<Icon icon="logos:google-sheets" className="size-4" />}>
Depuis Sheets
</DisabledMenuItem>
</MenubarSubContent>
</DocsExclusiveMenuSub>
<DocsExclusiveMenuSub id="insert-symbols">
<MenubarSubTrigger className="docs-menu-item">
<MenuIcon>
<Smile className="size-4" />
</MenuIcon>
Symboles
</MenubarSubTrigger>
<MenubarSubContent
className="docs-menu-content docs-menu-sub-content min-w-[200px] overflow-visible"
data-docs-menu-surface
>
<DisabledMenuItem icon={<Smile className="size-4" />}>Emoji</DisabledMenuItem>
<DisabledMenuItem icon={<span className="text-sm font-medium">Ω</span>}>
Caractères spéciaux
</DisabledMenuItem>
<DisabledMenuItem icon={<span className="text-sm font-medium">π²</span>}>
Équation
</DisabledMenuItem>
</MenubarSubContent>
</DocsExclusiveMenuSub>
</DocsExclusiveMenuSubRoot>
<MenubarSeparator />
<DisabledMenuItem icon={<Icon icon="material-symbols:tab" className="size-4" />} shortcut="Maj+F11">
Onglet
</DisabledMenuItem>
<MenubarItem
className="docs-menu-item"
disabled={disabled}
onClick={actions.onInsertHorizontalRule}
>
<MenuIcon>
<Minus className="size-4" />
</MenuIcon>
Ligne horizontale
</MenubarItem>
<DocsExclusiveMenuSub id="insert-break">
<MenubarSubTrigger className="docs-menu-item">
<MenuIcon>
<Icon icon="material-symbols:page-break" className="size-4" />
</MenuIcon>
Saut
</MenubarSubTrigger>
<MenubarSubContent
className="docs-menu-content docs-menu-sub-content min-w-[280px] overflow-visible"
data-docs-menu-surface
>
<DisabledMenuItem
icon={<Icon icon="material-symbols:page-break" className="size-4" />}
shortcut="⌘↵"
>
Saut de page
</DisabledMenuItem>
<DisabledMenuItem icon={<Icon icon="material-symbols:view-column" className="size-4" />}>
Saut de colonne
</DisabledMenuItem>
<DisabledMenuItem icon={<Icon icon="material-symbols:subdirectory-arrow-right" className="size-4" />}>
Saut de section (page suivante)
</DisabledMenuItem>
<DisabledMenuItem icon={<Icon icon="material-symbols:subdirectory-arrow-right" className="size-4" />}>
Saut de section (continu)
</DisabledMenuItem>
</MenubarSubContent>
</DocsExclusiveMenuSub>
<DisabledMenuItem icon={<Bookmark className="size-4" />}>Signet</DisabledMenuItem>
<DocsExclusiveMenuSub id="insert-page-elements">
<MenubarSubTrigger className="docs-menu-item">
<MenuIcon>
<Icon icon="material-symbols:article-outline" className="size-4" />
</MenuIcon>
Éléments de page
<DocsMenuBadge>Mise à jour</DocsMenuBadge>
</MenubarSubTrigger>
<MenubarSubContent
className="docs-menu-content docs-menu-sub-content min-w-[300px] overflow-visible"
data-docs-menu-surface
>
<DocsExclusiveMenuSub id="insert-toc">
<MenubarSubTrigger className="docs-menu-item" disabled>
<MenuIcon>
<Icon icon="material-symbols:list-alt" className="size-4" />
</MenuIcon>
Table des matières
</MenubarSubTrigger>
<MenubarSubContent
className="docs-menu-content docs-menu-sub-content min-w-[280px] overflow-visible"
data-docs-menu-surface
>
<DisabledMenuItem icon={<Icon icon="material-symbols:list-alt" className="size-4" />}>
Table des matières avec liens
</DisabledMenuItem>
<DisabledMenuItem icon={<Icon icon="material-symbols:format-list-bulleted" className="size-4" />}>
Table des matières en texte brut
</DisabledMenuItem>
</MenubarSubContent>
</DocsExclusiveMenuSub>
<MenubarItem
className="docs-menu-item"
disabled={pageElementsDisabled}
onClick={actions.onInsertHeader}
>
<MenuIcon>
<Icon icon="material-symbols:vertical-align-top" className="size-4" />
</MenuIcon>
En-tête
<span className="docs-menu-shortcut-sequence ml-auto text-xs text-[#5f6368] dark:text-muted-foreground">
Ctrl+O Ctrl+H
</span>
</MenubarItem>
<MenubarItem
className="docs-menu-item"
disabled={pageElementsDisabled}
onClick={actions.onInsertFooter}
>
<MenuIcon>
<Icon icon="material-symbols:vertical-align-bottom" className="size-4" />
</MenuIcon>
Pied de page
<span className="docs-menu-shortcut-sequence ml-auto text-xs text-[#5f6368] dark:text-muted-foreground">
Ctrl+O Ctrl+F
</span>
</MenubarItem>
<MenubarItem
className="docs-menu-item"
disabled={pageElementsDisabled}
onClick={actions.onInsertWatermark}
>
<MenuIcon>
<Icon icon="material-symbols:branding-watermark-outline" className="size-4" />
</MenuIcon>
Filigrane
</MenubarItem>
<DocsExclusiveMenuSub id="insert-page-numbers">
<MenubarSubTrigger className="docs-menu-item" disabled={pageElementsDisabled}>
<MenuIcon>
<span className="text-sm font-medium">#</span>
</MenuIcon>
Numéros de page
</MenubarSubTrigger>
<MenubarSubContent
className="docs-menu-content docs-menu-sub-content min-w-[240px] overflow-visible"
data-docs-menu-surface
>
<MenubarItem
className="docs-menu-item"
disabled={pageElementsDisabled}
onClick={actions.onInsertPageNumbersHeader}
>
<MenuIcon>
<Icon icon="material-symbols:vertical-align-top" className="size-4" />
</MenuIcon>
En haut de page
</MenubarItem>
<MenubarItem
className="docs-menu-item"
disabled={pageElementsDisabled}
onClick={actions.onInsertPageNumbersFooter}
>
<MenuIcon>
<Icon icon="material-symbols:vertical-align-bottom" className="size-4" />
</MenuIcon>
En bas de page
</MenubarItem>
<MenubarSeparator />
<MenubarItem
className="docs-menu-item"
disabled={pageElementsDisabled}
onClick={actions.onOpenPageNumbersOptions}
>
Options de numérotation
</MenubarItem>
</MenubarSubContent>
</DocsExclusiveMenuSub>
<DisabledMenuItem
icon={<Icon icon="material-symbols:notes" className="size-4" />}
shortcut="⌘⌥F"
>
Note de bas de page
</DisabledMenuItem>
</MenubarSubContent>
</DocsExclusiveMenuSub>
<MenubarSeparator />
<DisabledMenuItem icon={<MessageSquarePlus className="size-4" />} shortcut="⌘⌥M">
Commentaire
</DisabledMenuItem>
</MenubarContent>
</MenubarMenu>
)
}