Merge branch 'nostr-mention' into 'main'
Lexical: display only the username in mentions, trim Nostr mentions See merge request soapbox-pub/soapbox!2811
This commit is contained in:
commit
75179cc0b1
|
@ -52,7 +52,7 @@ interface IComposeEditor {
|
||||||
const theme: InitialConfigType['theme'] = {
|
const theme: InitialConfigType['theme'] = {
|
||||||
emoji: 'select-none',
|
emoji: 'select-none',
|
||||||
hashtag: 'hover:underline text-primary-600 dark:text-accent-blue hover:text-primary-800 dark:hover:text-accent-blue',
|
hashtag: 'hover:underline text-primary-600 dark:text-accent-blue hover:text-primary-800 dark:hover:text-accent-blue',
|
||||||
mention: 'hover:underline text-primary-600 dark:text-accent-blue hover:text-primary-800 dark:hover:text-accent-blue',
|
mention: 'hover:underline text-primary-600 dark:text-accent-blue hover:text-primary-800 dark:hover:text-accent-blue select-none',
|
||||||
link: 'hover:underline text-primary-600 dark:text-accent-blue hover:text-primary-800 dark:hover:text-accent-blue',
|
link: 'hover:underline text-primary-600 dark:text-accent-blue hover:text-primary-800 dark:hover:text-accent-blue',
|
||||||
text: {
|
text: {
|
||||||
bold: 'font-bold',
|
bold: 'font-bold',
|
||||||
|
|
|
@ -1,73 +0,0 @@
|
||||||
/**
|
|
||||||
* This source code is derived from code from Meta Platforms, Inc.
|
|
||||||
* and affiliates, licensed under the MIT license located in the
|
|
||||||
* LICENSE file in the /src/features/compose/editor directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { addClassNamesToElement } from '@lexical/utils';
|
|
||||||
import { $applyNodeReplacement, TextNode } from 'lexical';
|
|
||||||
|
|
||||||
import type {
|
|
||||||
EditorConfig,
|
|
||||||
LexicalNode,
|
|
||||||
NodeKey,
|
|
||||||
SerializedTextNode,
|
|
||||||
} from 'lexical';
|
|
||||||
|
|
||||||
class MentionNode extends TextNode {
|
|
||||||
|
|
||||||
static getType(): string {
|
|
||||||
return 'mention';
|
|
||||||
}
|
|
||||||
|
|
||||||
static clone(node: MentionNode): MentionNode {
|
|
||||||
return new MentionNode(node.__text, node.__key);
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(text: string, key?: NodeKey) {
|
|
||||||
super(text, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
createDOM(config: EditorConfig): HTMLElement {
|
|
||||||
const element = super.createDOM(config);
|
|
||||||
addClassNamesToElement(element, config.theme.mention);
|
|
||||||
return element;
|
|
||||||
}
|
|
||||||
|
|
||||||
static importJSON(serializedNode: SerializedTextNode): MentionNode {
|
|
||||||
const node = $createMentionNode(serializedNode.text);
|
|
||||||
node.setFormat(serializedNode.format);
|
|
||||||
node.setDetail(serializedNode.detail);
|
|
||||||
node.setMode(serializedNode.mode);
|
|
||||||
node.setStyle(serializedNode.style);
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
exportJSON(): SerializedTextNode {
|
|
||||||
return {
|
|
||||||
...super.exportJSON(),
|
|
||||||
type: 'mention',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
canInsertTextBefore(): boolean {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
isTextEntity(): true {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function $createMentionNode(text: string): MentionNode {
|
|
||||||
const node = new MentionNode(text);
|
|
||||||
node.setMode('segmented').toggleDirectionless();
|
|
||||||
return $applyNodeReplacement(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
const $isMentionNode = (
|
|
||||||
node: LexicalNode | null | undefined,
|
|
||||||
): node is MentionNode => node instanceof MentionNode;
|
|
||||||
|
|
||||||
export { MentionNode, $createMentionNode, $isMentionNode };
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
/**
|
||||||
|
* This source code is derived from code from Meta Platforms, Inc.
|
||||||
|
* and affiliates, licensed under the MIT license located in the
|
||||||
|
* LICENSE file in the /src/features/compose/editor directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { addClassNamesToElement } from '@lexical/utils';
|
||||||
|
import { $applyNodeReplacement, DecoratorNode } from 'lexical';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { Tooltip } from 'soapbox/components/ui';
|
||||||
|
import { isPubkey } from 'soapbox/utils/nostr';
|
||||||
|
|
||||||
|
import type {
|
||||||
|
EditorConfig,
|
||||||
|
LexicalNode,
|
||||||
|
NodeKey,
|
||||||
|
SerializedLexicalNode,
|
||||||
|
Spread,
|
||||||
|
} from 'lexical';
|
||||||
|
|
||||||
|
type SerializedMentionNode = Spread<{
|
||||||
|
acct: string;
|
||||||
|
type: 'mention';
|
||||||
|
version: 1;
|
||||||
|
}, SerializedLexicalNode>;
|
||||||
|
|
||||||
|
class MentionNode extends DecoratorNode<JSX.Element> {
|
||||||
|
|
||||||
|
__acct: string;
|
||||||
|
|
||||||
|
static getType(): string {
|
||||||
|
return 'mention';
|
||||||
|
}
|
||||||
|
|
||||||
|
static clone(node: MentionNode): MentionNode {
|
||||||
|
return new MentionNode(node.__acct, node.__key);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(acct: string, key?: NodeKey) {
|
||||||
|
super(key);
|
||||||
|
this.__acct = acct;
|
||||||
|
}
|
||||||
|
|
||||||
|
createDOM(config: EditorConfig): HTMLElement {
|
||||||
|
const span = document.createElement('span');
|
||||||
|
addClassNamesToElement(span, config.theme.mention);
|
||||||
|
return span;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDOM(): false {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static importJSON(serializedNode: SerializedMentionNode): MentionNode {
|
||||||
|
const node = $createMentionNode(serializedNode.acct);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
exportJSON(): SerializedMentionNode {
|
||||||
|
return {
|
||||||
|
type: 'mention',
|
||||||
|
acct: this.__acct,
|
||||||
|
version: 1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
getTextContent(): string {
|
||||||
|
return `@${this.__acct}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
canInsertTextBefore(): boolean {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
isTextEntity(): true {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
decorate(): JSX.Element {
|
||||||
|
const acct = this.__acct;
|
||||||
|
const username = acct.split('@')[0];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tooltip text={`@${acct}`}>
|
||||||
|
<button
|
||||||
|
className='text-accent-blue'
|
||||||
|
type='button'
|
||||||
|
dir='ltr'
|
||||||
|
>
|
||||||
|
@{isPubkey(username) ? username.slice(0, 8) : username}
|
||||||
|
</button>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function $createMentionNode(acct: string): MentionNode {
|
||||||
|
const node = new MentionNode(acct);
|
||||||
|
return $applyNodeReplacement(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
const $isMentionNode = (
|
||||||
|
node: LexicalNode | null | undefined,
|
||||||
|
): node is MentionNode => node instanceof MentionNode;
|
||||||
|
|
||||||
|
export { MentionNode, $createMentionNode, $isMentionNode };
|
|
@ -328,7 +328,7 @@ const AutosuggestPlugin = ({
|
||||||
node.select();
|
node.select();
|
||||||
} else {
|
} else {
|
||||||
const acct = selectAccount(getState(), suggestion)!.acct;
|
const acct = selectAccount(getState(), suggestion)!.acct;
|
||||||
replaceMatch($createMentionNode(`@${acct}`));
|
replaceMatch($createMentionNode(acct));
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch(clearComposeSuggestions(composeId));
|
dispatch(clearComposeSuggestions(composeId));
|
||||||
|
|
Loading…
Reference in New Issue