- Updated .env.example to include configuration for OnlyOffice Document Server. - Modified the workspace configuration to remove the drive-suite path. - Adjusted TypeScript environment imports for consistency. - Enhanced Next.js configuration to disable canvas in Webpack. - Updated package.json to include new dependencies for OnlyOffice and PDF.js. - Added global styles for OnlyOffice theme integration in the CSS. - Created new layout and page components for the Drive feature, including public sharing and editing functionalities. - Updated metadata handling across various layouts to reflect the new app structure.
128 lines
3.2 KiB
TypeScript
128 lines
3.2 KiB
TypeScript
"use client"
|
|
|
|
import { useEffect, useRef, useState } from "react"
|
|
import { Button } from "@/components/ui/button"
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogDescription,
|
|
DialogFooter,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
} from "@/components/ui/dialog"
|
|
import { Input } from "@/components/ui/input"
|
|
import {
|
|
DRIVE_BTN_GHOST,
|
|
DRIVE_BTN_PRIMARY,
|
|
DRIVE_DIALOG_BODY,
|
|
DRIVE_DIALOG_CONTENT,
|
|
DRIVE_DIALOG_FOOTER,
|
|
DRIVE_DIALOG_HEADER,
|
|
DRIVE_DIALOG_OVERLAY,
|
|
DRIVE_FIELD_CLASS,
|
|
DRIVE_TEXT_SECONDARY,
|
|
DRIVE_TEXT_TITLE,
|
|
} from "@/lib/drive/drive-dialog-styles"
|
|
import { cn } from "@/lib/utils"
|
|
|
|
export function DriveNameDialog({
|
|
open,
|
|
onOpenChange,
|
|
title,
|
|
description,
|
|
defaultValue,
|
|
confirmLabel = "Créer",
|
|
onConfirm,
|
|
}: {
|
|
open: boolean
|
|
onOpenChange: (open: boolean) => void
|
|
title: string
|
|
description?: string
|
|
defaultValue: string
|
|
confirmLabel?: string
|
|
onConfirm: (name: string) => void | Promise<void>
|
|
}) {
|
|
const [value, setValue] = useState(defaultValue)
|
|
const [busy, setBusy] = useState(false)
|
|
const inputRef = useRef<HTMLInputElement>(null)
|
|
|
|
useEffect(() => {
|
|
if (!open) return
|
|
setValue(defaultValue)
|
|
const t = setTimeout(() => {
|
|
const el = inputRef.current
|
|
if (!el) return
|
|
el.focus()
|
|
el.select()
|
|
}, 0)
|
|
return () => clearTimeout(t)
|
|
}, [open, defaultValue])
|
|
|
|
const submit = async () => {
|
|
const trimmed = value.trim()
|
|
if (!trimmed || busy) return
|
|
setBusy(true)
|
|
try {
|
|
await onConfirm(trimmed)
|
|
onOpenChange(false)
|
|
} finally {
|
|
setBusy(false)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
<DialogContent
|
|
showCloseButton={!busy}
|
|
overlayClassName={DRIVE_DIALOG_OVERLAY}
|
|
className={cn(DRIVE_DIALOG_CONTENT, "sm:max-w-[420px]")}
|
|
onOpenAutoFocus={(e) => e.preventDefault()}
|
|
{...(description ? {} : { "aria-describedby": undefined })}
|
|
>
|
|
<DialogHeader className={DRIVE_DIALOG_HEADER}>
|
|
<DialogTitle className={cn("text-base font-medium", DRIVE_TEXT_TITLE)}>
|
|
{title}
|
|
</DialogTitle>
|
|
{description ? (
|
|
<DialogDescription className={cn("text-sm", DRIVE_TEXT_SECONDARY)}>
|
|
{description}
|
|
</DialogDescription>
|
|
) : null}
|
|
</DialogHeader>
|
|
<div className={DRIVE_DIALOG_BODY}>
|
|
<Input
|
|
ref={inputRef}
|
|
value={value}
|
|
onChange={(e) => setValue(e.target.value)}
|
|
onKeyDown={(e) => {
|
|
if (e.key === "Enter") void submit()
|
|
}}
|
|
disabled={busy}
|
|
autoComplete="off"
|
|
className={DRIVE_FIELD_CLASS}
|
|
/>
|
|
</div>
|
|
<DialogFooter className={DRIVE_DIALOG_FOOTER}>
|
|
<Button
|
|
type="button"
|
|
variant="ghost"
|
|
className={DRIVE_BTN_GHOST}
|
|
onClick={() => onOpenChange(false)}
|
|
disabled={busy}
|
|
>
|
|
Annuler
|
|
</Button>
|
|
<Button
|
|
type="button"
|
|
className={DRIVE_BTN_PRIMARY}
|
|
onClick={() => void submit()}
|
|
disabled={busy || !value.trim()}
|
|
>
|
|
{confirmLabel}
|
|
</Button>
|
|
</DialogFooter>
|
|
</DialogContent>
|
|
</Dialog>
|
|
)
|
|
}
|