Compare commits
1 Commits
fix/react-
...
feat/comme
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aff1d76010 |
@@ -10,6 +10,7 @@ import { t } from "@lingui/core/macro";
|
|||||||
import Link from "@tiptap/extension-link";
|
import Link from "@tiptap/extension-link";
|
||||||
import Mention from "@tiptap/extension-mention";
|
import Mention from "@tiptap/extension-mention";
|
||||||
import Placeholder from "@tiptap/extension-placeholder";
|
import Placeholder from "@tiptap/extension-placeholder";
|
||||||
|
import Typography from "@tiptap/extension-typography";
|
||||||
import {
|
import {
|
||||||
BubbleMenu,
|
BubbleMenu,
|
||||||
EditorContent,
|
EditorContent,
|
||||||
@@ -17,7 +18,6 @@ import {
|
|||||||
ReactRenderer,
|
ReactRenderer,
|
||||||
useEditor,
|
useEditor,
|
||||||
} from "@tiptap/react";
|
} from "@tiptap/react";
|
||||||
import Typography from "@tiptap/extension-typography";
|
|
||||||
import StarterKit from "@tiptap/starter-kit";
|
import StarterKit from "@tiptap/starter-kit";
|
||||||
import Suggestion from "@tiptap/suggestion";
|
import Suggestion from "@tiptap/suggestion";
|
||||||
import {
|
import {
|
||||||
@@ -440,6 +440,7 @@ export default function Editor({
|
|||||||
content,
|
content,
|
||||||
onChange,
|
onChange,
|
||||||
onBlur,
|
onBlur,
|
||||||
|
onSubmit,
|
||||||
readOnly = false,
|
readOnly = false,
|
||||||
workspaceMembers,
|
workspaceMembers,
|
||||||
enableYouTubeEmbed = true,
|
enableYouTubeEmbed = true,
|
||||||
@@ -449,6 +450,7 @@ export default function Editor({
|
|||||||
content: string | null;
|
content: string | null;
|
||||||
onChange?: (value: string) => void;
|
onChange?: (value: string) => void;
|
||||||
onBlur?: () => void;
|
onBlur?: () => void;
|
||||||
|
onSubmit?: () => void;
|
||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
workspaceMembers: WorkspaceMember[];
|
workspaceMembers: WorkspaceMember[];
|
||||||
enableYouTubeEmbed?: boolean;
|
enableYouTubeEmbed?: boolean;
|
||||||
@@ -461,12 +463,16 @@ export default function Editor({
|
|||||||
// in refs to avoid the editor capturing stale closures on re-render.
|
// in refs to avoid the editor capturing stale closures on re-render.
|
||||||
const onChangeRef = useRef(onChange);
|
const onChangeRef = useRef(onChange);
|
||||||
const onBlurRef = useRef(onBlur);
|
const onBlurRef = useRef(onBlur);
|
||||||
|
const onSubmitRef = useRef(onSubmit);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
onChangeRef.current = onChange;
|
onChangeRef.current = onChange;
|
||||||
}, [onChange]);
|
}, [onChange]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
onBlurRef.current = onBlur;
|
onBlurRef.current = onBlur;
|
||||||
}, [onBlur]);
|
}, [onBlur]);
|
||||||
|
useEffect(() => {
|
||||||
|
onSubmitRef.current = onSubmit;
|
||||||
|
}, [onSubmit]);
|
||||||
|
|
||||||
const editor = useEditor(
|
const editor = useEditor(
|
||||||
{
|
{
|
||||||
@@ -489,8 +495,8 @@ export default function Editor({
|
|||||||
Placeholder.configure({
|
Placeholder.configure({
|
||||||
placeholder: readOnly
|
placeholder: readOnly
|
||||||
? ""
|
? ""
|
||||||
: placeholder ??
|
: (placeholder ??
|
||||||
t`Add description... (type '/' to open commands or '@' to mention)`,
|
t`Add description... (type '/' to open commands or '@' to mention)`),
|
||||||
}),
|
}),
|
||||||
SlashCommands.configure({
|
SlashCommands.configure({
|
||||||
commandItems: getCommandItems(disableHeadings),
|
commandItems: getCommandItems(disableHeadings),
|
||||||
@@ -508,24 +514,26 @@ export default function Editor({
|
|||||||
suggestion: {
|
suggestion: {
|
||||||
char: "@",
|
char: "@",
|
||||||
items: ({ query }: { query: string }) => {
|
items: ({ query }: { query: string }) => {
|
||||||
const withEmail = workspaceMembers.filter((member) => member.email);
|
const withEmail = workspaceMembers.filter(
|
||||||
|
(member) => member.email,
|
||||||
|
);
|
||||||
|
|
||||||
const mapped = withEmail.map((member: WorkspaceMember) => ({
|
const mapped = withEmail.map((member: WorkspaceMember) => ({
|
||||||
id: member.publicId,
|
id: member.publicId,
|
||||||
label: member?.user?.name?.trim() || member.email || "",
|
label: member?.user?.name?.trim() || member.email || "",
|
||||||
image: member?.user?.image ?? null,
|
image: member?.user?.image ?? null,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const all: MentionItem[] = mapped.filter(
|
const all: MentionItem[] = mapped.filter(
|
||||||
(item) => item.label && item.label.length > 0,
|
(item) => item.label && item.label.length > 0,
|
||||||
);
|
);
|
||||||
|
|
||||||
const q = query.toLowerCase().trim();
|
const q = query.toLowerCase().trim();
|
||||||
|
|
||||||
if (q === "") {
|
if (q === "") {
|
||||||
return all;
|
return all;
|
||||||
}
|
}
|
||||||
|
|
||||||
const filtered = all.filter((u) =>
|
const filtered = all.filter((u) =>
|
||||||
u.label.toLowerCase().includes(q),
|
u.label.toLowerCase().includes(q),
|
||||||
);
|
);
|
||||||
@@ -551,15 +559,15 @@ export default function Editor({
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
Typography.configure({
|
Typography.configure({
|
||||||
openDoubleQuote: false,
|
openDoubleQuote: false,
|
||||||
closeDoubleQuote: false,
|
closeDoubleQuote: false,
|
||||||
openSingleQuote: false,
|
openSingleQuote: false,
|
||||||
closeSingleQuote: false,
|
closeSingleQuote: false,
|
||||||
oneHalf: false,
|
oneHalf: false,
|
||||||
oneQuarter: false,
|
oneQuarter: false,
|
||||||
threeQuarters: false,
|
threeQuarters: false,
|
||||||
superscriptTwo: false,
|
superscriptTwo: false,
|
||||||
superscriptThree: false,
|
superscriptThree: false,
|
||||||
}),
|
}),
|
||||||
...(enableYouTubeEmbed ? [YouTubeNode] : []),
|
...(enableYouTubeEmbed ? [YouTubeNode] : []),
|
||||||
],
|
],
|
||||||
@@ -581,6 +589,13 @@ export default function Editor({
|
|||||||
attributes: {
|
attributes: {
|
||||||
class: "outline-none focus:outline-none focus-visible:ring-0",
|
class: "outline-none focus:outline-none focus-visible:ring-0",
|
||||||
},
|
},
|
||||||
|
handleKeyDown: (_view, event) => {
|
||||||
|
if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
|
||||||
|
onSubmitRef.current?.();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
editable: !readOnly,
|
editable: !readOnly,
|
||||||
injectCSS: false,
|
injectCSS: false,
|
||||||
|
|||||||
@@ -2,9 +2,10 @@ import { t } from "@lingui/core/macro";
|
|||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { HiOutlineArrowUp } from "react-icons/hi2";
|
import { HiOutlineArrowUp } from "react-icons/hi2";
|
||||||
|
|
||||||
import Editor from "~/components/Editor";
|
|
||||||
import type { WorkspaceMember } from "~/components/Editor";
|
import type { WorkspaceMember } from "~/components/Editor";
|
||||||
|
import Editor from "~/components/Editor";
|
||||||
import LoadingSpinner from "~/components/LoadingSpinner";
|
import LoadingSpinner from "~/components/LoadingSpinner";
|
||||||
|
import { Tooltip } from "~/components/Tooltip";
|
||||||
import { usePermissions } from "~/hooks/usePermissions";
|
import { usePermissions } from "~/hooks/usePermissions";
|
||||||
import { usePopup } from "~/providers/popup";
|
import { usePopup } from "~/providers/popup";
|
||||||
import { api } from "~/utils/api";
|
import { api } from "~/utils/api";
|
||||||
@@ -51,6 +52,21 @@ const NewCommentForm = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isMac =
|
||||||
|
typeof navigator !== "undefined" && navigator.userAgent.includes("Mac");
|
||||||
|
|
||||||
|
const submitTooltip = (
|
||||||
|
<div className="flex flex-row items-center gap-2 text-[11px]">
|
||||||
|
{t`Submit`}
|
||||||
|
<span className="inline-flex items-center justify-center rounded border border-light-400 bg-light-200 px-1.5 py-0.5 font-mono text-[8px] font-semibold text-neutral-900 dark:border-dark-400 dark:bg-dark-200 dark:text-dark-950">
|
||||||
|
{isMac ? "⌘" : "Ctrl"}
|
||||||
|
</span>
|
||||||
|
<span className="inline-flex items-center justify-center rounded border border-light-400 bg-light-200 px-1.5 py-0.5 font-mono text-[8px] font-semibold text-neutral-900 dark:border-dark-400 dark:bg-dark-200 dark:text-dark-950">
|
||||||
|
Enter
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
if (!canCreateComment) {
|
if (!canCreateComment) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -63,23 +79,26 @@ const NewCommentForm = ({
|
|||||||
<Editor
|
<Editor
|
||||||
content={watch("comment")}
|
content={watch("comment")}
|
||||||
onChange={(value) => setValue("comment", value)}
|
onChange={(value) => setValue("comment", value)}
|
||||||
|
onSubmit={handleSubmit(onSubmit)}
|
||||||
workspaceMembers={workspaceMembers}
|
workspaceMembers={workspaceMembers}
|
||||||
enableYouTubeEmbed={false}
|
enableYouTubeEmbed={false}
|
||||||
placeholder={t`Add comment... (type '/' to open commands or '@' to mention)`}
|
placeholder={t`Add comment... (type '/' to open commands or '@' to mention)`}
|
||||||
disableHeadings={true}
|
disableHeadings={true}
|
||||||
/>
|
/>
|
||||||
<div className="flex justify-end">
|
<div className="flex justify-end">
|
||||||
<button
|
<Tooltip content={submitTooltip} placement="top">
|
||||||
type="submit"
|
<button
|
||||||
disabled={addCommentMutation.isPending}
|
type="submit"
|
||||||
className="flex h-8 w-8 items-center justify-center rounded-full border border-light-600 bg-light-300 hover:bg-light-400 disabled:opacity-50 dark:border-dark-400 dark:bg-dark-200 dark:hover:bg-dark-400"
|
disabled={addCommentMutation.isPending}
|
||||||
>
|
className="flex h-8 w-8 items-center justify-center rounded-full border border-light-600 bg-light-300 hover:bg-light-400 disabled:opacity-50 dark:border-dark-400 dark:bg-dark-200 dark:hover:bg-dark-400"
|
||||||
{addCommentMutation.isPending ? (
|
>
|
||||||
<LoadingSpinner size="sm" />
|
{addCommentMutation.isPending ? (
|
||||||
) : (
|
<LoadingSpinner size="sm" />
|
||||||
<HiOutlineArrowUp />
|
) : (
|
||||||
)}
|
<HiOutlineArrowUp />
|
||||||
</button>
|
)}
|
||||||
|
</button>
|
||||||
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user