Add a button to upload images into comments (#6092)
This commit is contained in:
@@ -50,7 +50,7 @@ export type Props = Optional<
|
||||
previewsDisabled?: boolean;
|
||||
onHeadingsChange?: (headings: Heading[]) => void;
|
||||
onSynced?: () => Promise<void>;
|
||||
onPublish?: (event: React.MouseEvent) => any;
|
||||
onPublish?: (event: React.MouseEvent) => void;
|
||||
editorStyle?: React.CSSProperties;
|
||||
};
|
||||
|
||||
@@ -138,7 +138,7 @@ function Editor(props: Props, ref: React.RefObject<SharedEditor> | null) {
|
||||
: 1
|
||||
);
|
||||
},
|
||||
[documents]
|
||||
[locale, documents]
|
||||
);
|
||||
|
||||
const handleUploadFile = React.useCallback(
|
||||
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
import { Decoration, EditorView, NodeViewConstructor } from "prosemirror-view";
|
||||
import * as React from "react";
|
||||
import styled, { css, DefaultTheme, ThemeProps } from "styled-components";
|
||||
import insertFiles from "@shared/editor/commands/insertFiles";
|
||||
import Styles from "@shared/editor/components/Styles";
|
||||
import { EmbedDescriptor } from "@shared/editor/embeds";
|
||||
import Extension, { CommandFactory } from "@shared/editor/lib/Extension";
|
||||
@@ -584,6 +585,25 @@ export class Editor extends React.PureComponent<
|
||||
window?.getSelection()?.removeAllRanges();
|
||||
};
|
||||
|
||||
/**
|
||||
* Insert files at the current selection.
|
||||
* =
|
||||
* @param event The source event
|
||||
* @param files The files to insert
|
||||
* @returns True if the files were inserted
|
||||
*/
|
||||
public insertFiles = (
|
||||
event: React.ChangeEvent<HTMLInputElement>,
|
||||
files: File[]
|
||||
) =>
|
||||
insertFiles(
|
||||
this.view,
|
||||
event,
|
||||
this.view.state.selection.to,
|
||||
files,
|
||||
this.props
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns true if the trimmed content of the editor is an empty string.
|
||||
*
|
||||
|
||||
@@ -1,16 +1,22 @@
|
||||
import { m } from "framer-motion";
|
||||
import { action } from "mobx";
|
||||
import { observer } from "mobx-react";
|
||||
import { ImageIcon } from "outline-icons";
|
||||
import * as React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { VisuallyHidden } from "reakit";
|
||||
import { toast } from "sonner";
|
||||
import { useTheme } from "styled-components";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { CommentValidation } from "@shared/validations";
|
||||
import { getEventFiles } from "@shared/utils/files";
|
||||
import { AttachmentValidation, CommentValidation } from "@shared/validations";
|
||||
import Comment from "~/models/Comment";
|
||||
import Avatar from "~/components/Avatar";
|
||||
import ButtonSmall from "~/components/ButtonSmall";
|
||||
import { useDocumentContext } from "~/components/DocumentContext";
|
||||
import Flex from "~/components/Flex";
|
||||
import NudeButton from "~/components/NudeButton";
|
||||
import Tooltip from "~/components/Tooltip";
|
||||
import type { Editor as SharedEditor } from "~/editor";
|
||||
import useCurrentUser from "~/hooks/useCurrentUser";
|
||||
import useOnClickOutside from "~/hooks/useOnClickOutside";
|
||||
@@ -64,6 +70,8 @@ function CommentForm({
|
||||
const editorRef = React.useRef<SharedEditor>(null);
|
||||
const [forceRender, setForceRender] = React.useState(0);
|
||||
const [inputFocused, setInputFocused] = React.useState(autoFocus);
|
||||
const file = React.useRef<HTMLInputElement>(null);
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
const { comments } = useStores();
|
||||
const user = useCurrentUser();
|
||||
@@ -188,6 +196,23 @@ function CommentForm({
|
||||
onBlur?.();
|
||||
};
|
||||
|
||||
const handleFilePicked = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
const files = getEventFiles(event);
|
||||
if (!files.length) {
|
||||
return;
|
||||
}
|
||||
editorRef.current?.insertFiles(event, files);
|
||||
};
|
||||
|
||||
const handleImageUpload = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
file.current?.click();
|
||||
};
|
||||
|
||||
// Focus the editor when it's a new comment just mounted, after a delay as the
|
||||
// editor is mounted within a fade transition.
|
||||
React.useEffect(() => {
|
||||
@@ -227,6 +252,15 @@ function CommentForm({
|
||||
{...presence}
|
||||
{...rest}
|
||||
>
|
||||
<VisuallyHidden>
|
||||
<input
|
||||
ref={file}
|
||||
type="file"
|
||||
onChange={handleFilePicked}
|
||||
accept={AttachmentValidation.imageContentTypes.join(", ")}
|
||||
tabIndex={-1}
|
||||
/>
|
||||
</VisuallyHidden>
|
||||
<Flex gap={8} align="flex-start" reverse={dir === "rtl"}>
|
||||
<Avatar model={user} size={24} style={{ marginTop: 8 }} />
|
||||
<Bubble
|
||||
@@ -256,13 +290,20 @@ function CommentForm({
|
||||
}
|
||||
/>
|
||||
{(inputFocused || data) && (
|
||||
<Flex justify={dir === "rtl" ? "flex-end" : "flex-start"} gap={8}>
|
||||
<ButtonSmall type="submit" borderOnHover>
|
||||
{thread && !thread.isNew ? t("Reply") : t("Post")}
|
||||
</ButtonSmall>
|
||||
<ButtonSmall onClick={handleCancel} neutral borderOnHover>
|
||||
{t("Cancel")}
|
||||
</ButtonSmall>
|
||||
<Flex justify="space-between" reverse={dir === "rtl"} gap={8}>
|
||||
<Flex gap={8}>
|
||||
<ButtonSmall type="submit" borderOnHover>
|
||||
{thread && !thread.isNew ? t("Reply") : t("Post")}
|
||||
</ButtonSmall>
|
||||
<ButtonSmall onClick={handleCancel} neutral borderOnHover>
|
||||
{t("Cancel")}
|
||||
</ButtonSmall>
|
||||
</Flex>
|
||||
<Tooltip delay={500} tooltip={t("Upload image")} placement="top">
|
||||
<NudeButton onClick={handleImageUpload}>
|
||||
<ImageIcon color={theme.textTertiary} />
|
||||
</NudeButton>
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
)}
|
||||
</Bubble>
|
||||
|
||||
@@ -500,6 +500,7 @@
|
||||
"Reply": "Reply",
|
||||
"Post": "Post",
|
||||
"Cancel": "Cancel",
|
||||
"Upload image": "Upload image",
|
||||
"No comments yet": "No comments yet",
|
||||
"Error updating comment": "Error updating comment",
|
||||
"Images are still uploading.\nAre you sure you want to discard them?": "Images are still uploading.\nAre you sure you want to discard them?",
|
||||
|
||||
Reference in New Issue
Block a user