Preview mentions (#5571)

Co-authored-by: Tom Moor <tom.moor@gmail.com>
This commit is contained in:
Apoorv Mishra
2023-07-22 21:43:09 +05:30
committed by GitHub
parent dbd85d62cb
commit 5d71398ea6
27 changed files with 923 additions and 361 deletions

View File

@@ -5,7 +5,8 @@ import {
NodeType,
Schema,
} from "prosemirror-model";
import { Command, TextSelection } from "prosemirror-state";
import { Command, Plugin, TextSelection } from "prosemirror-state";
import { EditorView } from "prosemirror-view";
import { Primitive } from "utility-types";
import Suggestion from "../extensions/Suggestion";
import { MarkdownSerializerState } from "../lib/markdown/serializer";
@@ -68,6 +69,7 @@ export default class Mention extends Suggestion {
"data-type": node.attrs.type,
"data-id": node.attrs.modelId,
"data-actorId": node.attrs.actorId,
"data-url": `mention://${node.attrs.id}/${node.attrs.type}/${node.attrs.modelId}`,
},
node.attrs.label,
],
@@ -79,6 +81,31 @@ export default class Mention extends Suggestion {
return [mentionRule];
}
get plugins(): Plugin[] {
return [
new Plugin({
props: {
handleDOMEvents: {
mouseover: (view: EditorView, event: MouseEvent) => {
const target = (event.target as HTMLElement)?.closest("span");
if (
target instanceof HTMLSpanElement &&
this.editor.elementRef.current?.contains(target) &&
!target.className.includes("ProseMirror-widget") &&
(!view.editable || (view.editable && !view.hasFocus()))
) {
if (this.options.onHoverLink) {
return this.options.onHoverLink(target);
}
}
return false;
},
},
},
}),
];
}
commands({ type }: { type: NodeType; schema: Schema }) {
return (attrs: Record<string, Primitive>): Command =>
(state, dispatch) => {

View File

@@ -899,5 +899,14 @@
"Webhooks can be used to notify your application when events happen in {{appName}}. Events are sent as a https request with a JSON payload in near real-time.": "Webhooks can be used to notify your application when events happen in {{appName}}. Events are sent as a https request with a JSON payload in near real-time.",
"Inactive": "Inactive",
"Create a webhook": "Create a webhook",
"Never logged in": "Never logged in",
"Online now": "Online now",
"Online {{ timeAgo }}": "Online {{ timeAgo }}",
"Viewed just now": "Viewed just now",
"Viewed {{ timeAgo }}": "Viewed {{ timeAgo }}",
"You updated {{ timeAgo }}": "You updated {{ timeAgo }}",
"{{ user }} updated {{ timeAgo }}": "{{ user }} updated {{ timeAgo }}",
"You created {{ timeAgo }}": "You created {{ timeAgo }}",
"{{ user }} created {{ timeAgo }}": "{{ user }} created {{ timeAgo }}",
"Uploading": "Uploading"
}

View File

@@ -209,5 +209,19 @@ export const NotificationEventDefaults = {
[NotificationEventType.ExportCompleted]: true,
};
export enum UnfurlType {
Mention = "mention",
Document = "document",
}
export type Unfurl<T = unknown> = {
url?: string;
type: T;
title: string;
description: string;
thumbnailUrl?: string | null;
meta: Record<string, string>;
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type ProsemirrorData = Record<string, any>;

View File

@@ -1,4 +1,24 @@
/* eslint-disable import/no-duplicates */
import { subDays, subMonths, subWeeks, subYears } from "date-fns";
import {
de,
enUS,
es,
faIR,
fr,
it,
ja,
ko,
nl,
ptBR,
pt,
pl,
ru,
tr,
vi,
zhCN,
zhTW,
} from "date-fns/locale";
import type { DateFilter } from "../types";
export function subtractDate(date: Date, period: DateFilter) {
@@ -80,3 +100,35 @@ export function getCurrentDateTimeAsString(locales?: Intl.LocalesArgument) {
minute: "numeric",
});
}
const locales = {
de_DE: de,
en_US: enUS,
es_ES: es,
fa_IR: faIR,
fr_FR: fr,
it_IT: it,
ja_JP: ja,
ko_KR: ko,
nl_NL: nl,
pt_BR: ptBR,
pt_PT: pt,
pl_PL: pl,
ru_RU: ru,
tr_TR: tr,
vi_VN: vi,
zh_CN: zhCN,
zh_TW: zhTW,
};
/**
* Returns the date-fns locale object for the given user language preference.
*
* @param language The user language
* @returns The date-fns locale.
*/
export function dateLocale(language: string | null | undefined) {
return language ? locales[language] : undefined;
}
export { locales };

View File

@@ -0,0 +1,12 @@
const parseMentionUrl = (url: string) => {
const matches = url.match(
/^mention:\/\/([a-z0-9-]+)\/([a-z]+)\/([a-z0-9-]+)$/
);
if (!matches) {
return {};
}
const [id, mentionType, modelId] = matches.slice(1);
return { id, mentionType, modelId };
};
export default parseMentionUrl;