diff --git a/docs/extensions/Image/index.md b/docs/extensions/Image/index.md index 2695f3f..278712d 100644 --- a/docs/extensions/Image/index.md +++ b/docs/extensions/Image/index.md @@ -34,3 +34,20 @@ const extensions = [ - ImageGif is a node extension that allows you to add an ImageGif to your editor. - More: [ImageGif](/extensions/ImageGif/index.md) + +## Props + +```ts +interface IImageOptions extends GeneralOptions { + /** Function for uploading files */ + upload?: (file: File) => Promise + + HTMLAttributes?: any + + acceptMimes?: string[] + maxSize?: number + + /** The source URL of the image */ + resourceImage: 'upload' | 'link' | 'both' +} +``` diff --git a/docs/extensions/Video/index.md b/docs/extensions/Video/index.md index 4693e0f..6cf98ed 100644 --- a/docs/extensions/Video/index.md +++ b/docs/extensions/Video/index.md @@ -29,3 +29,37 @@ const extensions = [ }), // [!code ++] ]; ``` + +## Props + +```ts +interface VideoOptions extends GeneralOptions { + /** + * Indicates whether fullscreen play is allowed + * + * @default true + */ + allowFullscreen: boolean + /** + * Indicates whether to display the frameborder + * + * @default false + */ + frameborder: boolean + /** + * Width of the video, can be a number or string + * + * @default VIDEO_SIZE['size-medium'] + */ + width: number | string + /** HTML attributes object for passing additional attributes */ + HTMLAttributes: { + [key: string]: any + } + /** Function for uploading files */ + upload?: (file: File) => Promise + + /** The source URL of the video */ + resourceVideo: 'upload' | 'link' | 'both' +} +``` diff --git a/src/extensions/Image/Image.ts b/src/extensions/Image/Image.ts index 968afbc..c34aec6 100644 --- a/src/extensions/Image/Image.ts +++ b/src/extensions/Image/Image.ts @@ -30,6 +30,7 @@ export interface SetImageAttrsOptions { const DEFAULT_OPTIONS: any = { acceptMimes: ['image/jpeg', 'image/gif', 'image/png', 'image/jpg'], maxSize: 1024 * 1024 * 5, // 5MB + resourceImage: 'both', } declare module '@tiptap/core' { @@ -59,6 +60,9 @@ export interface IImageOptions extends GeneralOptions { acceptMimes?: string[] maxSize?: number + + /** The source URL of the image */ + resourceImage: 'upload' | 'link' | 'both' } export const Image = TiptapImage.extend({ diff --git a/src/extensions/Image/components/ActionImageButton.tsx b/src/extensions/Image/components/ActionImageButton.tsx index fe65175..89f2e93 100644 --- a/src/extensions/Image/components/ActionImageButton.tsx +++ b/src/extensions/Image/components/ActionImageButton.tsx @@ -1,10 +1,11 @@ -import { useRef, useState } from 'react' +import { useMemo, useRef, useState } from 'react' import { ActionButton, Button, Checkbox, Input, Label, Tabs, TabsContent, TabsList, TabsTrigger } from '@/components' import { Dialog, DialogContent, DialogTitle, DialogTrigger } from '@/components/ui/dialog' import { ImageCropper } from '@/extensions/Image/components/ImageCropper' import { useLocale } from '@/locales' import { actionDialogImage, useDialogImage } from '@/extensions/Image/store' +import Image from '@/extensions/Image/Image' function ActionImageButton(props: any) { const { t } = useLocale() @@ -16,15 +17,20 @@ function ActionImageButton(props: any) { const [imageInline, setImageInline] = useState(false) + const uploadOptions = useMemo(() => { + const uploadOptions = props.editor.extensionManager.extensions.find( + (extension: any) => extension.name === Image.name, + )?.options + + return uploadOptions + }, [props.editor]) + async function handleFile(event: any) { const files = event?.target?.files if (!props.editor || props.editor.isDestroyed || files.length === 0) { return } const file = files[0] - const uploadOptions = props.editor.extensionManager.extensions.find( - (extension: any) => extension.name === 'image', - )?.options let src = '' if (uploadOptions.upload) { @@ -65,17 +71,29 @@ function ActionImageButton(props: any) { {t('editor.image.dialog.title')} - + - - {t('editor.image.dialog.tab.upload')} - {' '} - - - {' '} - {t('editor.image.dialog.tab.url')} - {' '} - + {uploadOptions.resourceImage === 'both' || uploadOptions.resourceImage === 'upload' + ? ( + + {t('editor.image.dialog.tab.upload')} + + ) + : <>} + {uploadOptions.resourceImage === 'both' || uploadOptions.resourceImage === 'link' + ? ( + + {t('editor.image.dialog.tab.url')} + + ) + : <>}
@@ -115,7 +133,7 @@ function ActionImageButton(props: any) {
setLink(e.target.value)} required diff --git a/src/extensions/Video/Video.ts b/src/extensions/Video/Video.ts index 5c5db1d..63babf3 100644 --- a/src/extensions/Video/Video.ts +++ b/src/extensions/Video/Video.ts @@ -33,6 +33,9 @@ export interface VideoOptions extends GeneralOptions { } /** Function for uploading files */ upload?: (file: File) => Promise + + /** The source URL of the video */ + resourceVideo: 'upload' | 'link' | 'both' } /** @@ -98,6 +101,7 @@ export const Video = Node.create({ allowFullscreen: true, upload: undefined, frameborder: false, + resourceVideo: 'both', width: VIDEO_SIZE['size-medium'], HTMLAttributes: { class: 'iframe-wrapper', diff --git a/src/extensions/Video/components/ActiveVideoButton.tsx b/src/extensions/Video/components/ActiveVideoButton.tsx index 8c4045b..0837037 100644 --- a/src/extensions/Video/components/ActiveVideoButton.tsx +++ b/src/extensions/Video/components/ActiveVideoButton.tsx @@ -1,4 +1,4 @@ -import { useRef, useState } from 'react' +import { useMemo, useRef, useState } from 'react' import { ActionButton, Button, Input, Tabs, TabsContent, TabsList, TabsTrigger } from '@/components' import { Dialog, DialogContent, DialogTitle, DialogTrigger } from '@/components/ui/dialog' @@ -19,15 +19,20 @@ function ActionVideoButton(props: any) { const dialogVideo = useDialogVideo() const [error, setError] = useState('') + const uploadOptions = useMemo(() => { + const uploadOptions = props.editor.extensionManager.extensions.find( + (extension: any) => extension.name === Video.name, + )?.options + + return uploadOptions + }, [props.editor]) + async function handleFile(event: any) { const files = event?.target?.files if (!props.editor || props.editor.isDestroyed || files.length === 0) { return } const file = files[0] - const uploadOptions = props.editor.extensionManager.extensions.find( - (extension: any) => extension.name === Video.name, - )?.options let src = '' if (uploadOptions.upload) { @@ -84,17 +89,23 @@ function ActionVideoButton(props: any) { {t('editor.video.dialog.title')} - + - - {t('editor.video.dialog.tab.upload')} - {' '} - - - {' '} - {t('editor.video.dialog.link')} - {' '} - + {(uploadOptions?.resourceVideo === 'both' || uploadOptions?.resourceVideo === 'upload') && ( + + {t('editor.video.dialog.tab.upload')} + + )} + {(uploadOptions?.resourceVideo === 'both' || uploadOptions?.resourceVideo === 'link') && ( + + {t('editor.video.dialog.link')} + + )} diff --git a/src/locales/en.ts b/src/locales/en.ts index dad44d4..f3efc2b 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -87,14 +87,14 @@ const locale = { 'editor.image.dialog.form.alt': 'Alt', 'editor.image.dialog.form.aspectRatio': 'Lock original aspect ratio', 'editor.image.dialog.form.file': 'File', - 'editor.image.dialog.button.apply': 'apply', + 'editor.image.dialog.button.apply': 'Apply', 'editor.video.tooltip': 'Video', 'editor.video.dialog.tab.upload': 'Upload', 'editor.video.dialog.uploading': 'Uploading', 'editor.video.dialog.title': 'Embed or upload a video', - 'editor.video.dialog.link': 'link', + 'editor.video.dialog.link': 'Link', 'editor.video.dialog.placeholder': 'Link', - 'editor.video.dialog.button.apply': 'apply', + 'editor.video.dialog.button.apply': 'Apply', 'editor.table.tooltip': 'Table', 'editor.table.menu.insert_table': 'Insert Table', 'editor.table.menu.insert_table.with_header_row': 'With header row', diff --git a/src/locales/pt-br.ts b/src/locales/pt-br.ts index cc0a91a..3352c5c 100644 --- a/src/locales/pt-br.ts +++ b/src/locales/pt-br.ts @@ -87,14 +87,14 @@ const locale = { 'editor.image.dialog.form.alt': 'Alt', 'editor.image.dialog.form.aspectRatio': 'Bloquear proporção original', 'editor.image.dialog.form.file': 'Arquivo', - 'editor.image.dialog.button.apply': 'aplicar', + 'editor.image.dialog.button.apply': 'Aplicar', 'editor.video.tooltip': 'Vídeo', 'editor.video.dialog.tab.upload': 'Enviar', 'editor.video.dialog.uploading': 'Enviando', 'editor.video.dialog.title': 'Incorporar ou enviar um vídeo', - 'editor.video.dialog.link': 'link', + 'editor.video.dialog.link': 'Link', 'editor.video.dialog.placeholder': 'Link', - 'editor.video.dialog.button.apply': 'aplicar', + 'editor.video.dialog.button.apply': 'Aplicar', 'editor.table.tooltip': 'Tabela', 'editor.table.menu.insert_table': 'Inserir tabela', 'editor.table.menu.insert_table.with_header_row': 'Com linha de cabeçalho', diff --git a/src/locales/vi.ts b/src/locales/vi.ts index 08ce501..75dc0e1 100644 --- a/src/locales/vi.ts +++ b/src/locales/vi.ts @@ -87,14 +87,14 @@ const locale = { 'editor.image.dialog.form.alt': 'Alt', 'editor.image.dialog.form.aspectRatio': 'Khóa tỷ lệ khung hình gốc', 'editor.image.dialog.form.file': 'Tệp', - 'editor.image.dialog.button.apply': 'áp dụng', + 'editor.image.dialog.button.apply': 'Áp dụng', 'editor.video.tooltip': 'Video', 'editor.video.dialog.tab.upload': 'Tải lên', 'editor.video.dialog.uploading': 'Đang tải lên', 'editor.video.dialog.title': 'Nhúng hoặc tải lên video', - 'editor.video.dialog.link': 'liên kết', + 'editor.video.dialog.link': 'Liên kết', 'editor.video.dialog.placeholder': 'Liên kết', - 'editor.video.dialog.button.apply': 'áp dụng', + 'editor.video.dialog.button.apply': 'Áp dụng', 'editor.table.tooltip': 'Bảng', 'editor.table.menu.insert_table': 'Chèn Bảng', 'editor.table.menu.insert_table.with_header_row': 'Có hàng tiêu đề',