Merge branch 'nostr-mention' into 'main'

Lexical: display only the username in mentions, trim Nostr mentions

See merge request soapbox-pub/soapbox!2811
environments/review-main-yi2y9f/deployments/4173
Alex Gleason 2023-10-13 22:59:09 +00:00
commit 75179cc0b1
4 zmienionych plików z 110 dodań i 75 usunięć

Wyświetl plik

@ -52,7 +52,7 @@ interface IComposeEditor {
const theme: InitialConfigType['theme'] = {
emoji: 'select-none',
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',
text: {
bold: 'font-bold',

Wyświetl plik

@ -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 };

Wyświetl plik

@ -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 };

Wyświetl plik

@ -328,7 +328,7 @@ const AutosuggestPlugin = ({
node.select();
} else {
const acct = selectAccount(getState(), suggestion)!.acct;
replaceMatch($createMentionNode(`@${acct}`));
replaceMatch($createMentionNode(acct));
}
dispatch(clearComposeSuggestions(composeId));