mirror of
https://github.com/naturalcrit/homebrewery.git
synced 2026-03-27 14:38:11 +00:00
emoji autocomplete
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
import { autocompletion } from '@codemirror/autocomplete';
|
||||||
|
|
||||||
import diceFont from '@themes/fonts/iconFonts/diceFont.js';
|
import diceFont from '@themes/fonts/iconFonts/diceFont.js';
|
||||||
import elderberryInn from '@themes/fonts/iconFonts/elderberryInn.js';
|
import elderberryInn from '@themes/fonts/iconFonts/elderberryInn.js';
|
||||||
import fontAwesome from '@themes/fonts/iconFonts/fontAwesome.js';
|
import fontAwesome from '@themes/fonts/iconFonts/fontAwesome.js';
|
||||||
@@ -10,75 +12,61 @@ const emojis = {
|
|||||||
...gameIcons
|
...gameIcons
|
||||||
};
|
};
|
||||||
|
|
||||||
const showAutocompleteEmoji = function(CodeMirror, editor) {
|
const emojiCompletionList = (context)=>{
|
||||||
CodeMirror.commands.autocomplete = function(editor) {
|
const word = context.matchBefore(/:[^\s:]*/);
|
||||||
editor.showHint({
|
if(!word) return null;
|
||||||
completeSingle : false,
|
|
||||||
hint : function(editor) {
|
|
||||||
const cursor = editor.getCursor();
|
|
||||||
const line = cursor.line;
|
|
||||||
const lineContent = editor.getLine(line);
|
|
||||||
const start = lineContent.lastIndexOf(':', cursor.ch - 1) + 1;
|
|
||||||
const end = cursor.ch;
|
|
||||||
const currentWord = lineContent.slice(start, end);
|
|
||||||
|
|
||||||
|
const line = context.state.doc.lineAt(context.pos);
|
||||||
|
const textToCursor = line.text.slice(0, context.pos - line.from);
|
||||||
|
|
||||||
const list = Object.keys(emojis).filter(function(emoji) {
|
if(textToCursor.includes('{')) {
|
||||||
return emoji.toLowerCase().indexOf(currentWord.toLowerCase()) >= 0;
|
const curlyToCursor = textToCursor.slice(textToCursor.indexOf('{'));
|
||||||
}).sort((a, b)=>{
|
const curlySpanRegex = /{(?=((?:[:=](?:"[\w,\-()#%. ]*"|[\w\-()#%.]*)|[^"':={}\s]*)*))\1$/g;
|
||||||
const lowerA = a.replace(/\d+/g, function(match) { // Temporarily convert any numbers in emoji string
|
if(curlySpanRegex.test(curlyToCursor)) return null;
|
||||||
return match.padStart(4, '0'); // to 4-digits, left-padded with 0's, to aid in
|
}
|
||||||
}).toLowerCase(); // sorting numbers, i.e., "d6, d10, d20", not "d10, d20, d6"
|
|
||||||
const lowerB = b.replace(/\d+/g, function(match) { // Also make lowercase for case-insensitive alpha sorting
|
|
||||||
return match.padStart(4, '0');
|
|
||||||
}).toLowerCase();
|
|
||||||
|
|
||||||
if(lowerA < lowerB)
|
const currentWord = word.text.slice(1); // remove ':'
|
||||||
return -1;
|
|
||||||
return 1;
|
|
||||||
}).map(function(emoji) {
|
|
||||||
return {
|
|
||||||
text : `${emoji}:`, // Text to output to editor when option is selected
|
|
||||||
render : function(element, self, data) { // How to display the option in the dropdown
|
|
||||||
const div = document.createElement('div');
|
|
||||||
div.innerHTML = `<i class="emojiPreview ${emojis[emoji]}"></i> ${emoji}`;
|
|
||||||
element.appendChild(div);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
const options = Object.keys(emojis)
|
||||||
list : list.length ? list : [],
|
.filter((e)=>e.toLowerCase().includes(currentWord.toLowerCase()))
|
||||||
from : CodeMirror.Pos(line, start),
|
.sort((a, b)=>{
|
||||||
to : CodeMirror.Pos(line, end)
|
const normalize = (str)=>str.replace(/\d+/g, (m)=>m.padStart(4, '0')).toLowerCase();
|
||||||
};
|
return normalize(a) < normalize(b) ? -1 : 1;
|
||||||
}
|
})
|
||||||
});
|
.map((e)=>({
|
||||||
|
label : e,
|
||||||
|
apply : `${e}:`,
|
||||||
|
type : 'text',
|
||||||
|
info : ()=>{
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.innerHTML = `<i class="emojiPreview ${emojis[e]}"></i> ${e}`;
|
||||||
|
return div;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
return {
|
||||||
|
from : word.from + 1,
|
||||||
|
options,
|
||||||
};
|
};
|
||||||
|
|
||||||
editor.on('inputRead', function(instance, change) {
|
|
||||||
const cursor = editor.getCursor();
|
|
||||||
const line = editor.getLine(cursor.line);
|
|
||||||
|
|
||||||
// Get the text from the start of the line to the cursor
|
|
||||||
const textToCursor = line.slice(0, cursor.ch);
|
|
||||||
|
|
||||||
// Do not autosuggest emojis in curly span/div/injector properties
|
|
||||||
if(line.includes('{')) {
|
|
||||||
const curlyToCursor = textToCursor.slice(textToCursor.indexOf(`{`));
|
|
||||||
const curlySpanRegex = /{(?=((?:[:=](?:"[\w,\-()#%. ]*"|[\w\-()#%.]*)|[^"':={}\s]*)*))\1$/g;
|
|
||||||
|
|
||||||
if(curlySpanRegex.test(curlyToCursor))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the text ends with ':xyz'
|
|
||||||
if(/:[^\s:]+$/.test(textToCursor)) {
|
|
||||||
CodeMirror.commands.autocomplete(editor);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
export const autocompleteEmoji = autocompletion({
|
||||||
showAutocompleteEmoji
|
override : [emojiCompletionList],
|
||||||
};
|
activateOnTyping : true,
|
||||||
|
addToOptions : [
|
||||||
|
{
|
||||||
|
render(completion) {
|
||||||
|
const e = completion.label;
|
||||||
|
|
||||||
|
const icon = document.createElement('i');
|
||||||
|
icon.className = `emojiPreview ${emojis[e]}`;
|
||||||
|
|
||||||
|
// append directly to a DocumentFragment to return a single node
|
||||||
|
const fragment = document.createDocumentFragment();
|
||||||
|
fragment.appendChild(icon);
|
||||||
|
|
||||||
|
return fragment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
@@ -18,6 +18,7 @@ import { defaultKeymap, history, historyField, undo, redo } from '@codemirror/co
|
|||||||
import { languages } from '@codemirror/language-data';
|
import { languages } from '@codemirror/language-data';
|
||||||
import { css } from '@codemirror/lang-css';
|
import { css } from '@codemirror/lang-css';
|
||||||
import { markdown, markdownLanguage } from '@codemirror/lang-markdown';
|
import { markdown, markdownLanguage } from '@codemirror/lang-markdown';
|
||||||
|
import { autocompleteEmoji } from './autocompleteEmoji.js';
|
||||||
|
|
||||||
import * as themes from '@uiw/codemirror-themes-all';
|
import * as themes from '@uiw/codemirror-themes-all';
|
||||||
const themeCompartment = new Compartment();
|
const themeCompartment = new Compartment();
|
||||||
@@ -31,20 +32,20 @@ import { legacyCustomHighlightStyle, legacyTokenizeCustomMarkdown } from './lega
|
|||||||
const createHighlightPlugin = (renderer, tab)=>{
|
const createHighlightPlugin = (renderer, tab)=>{
|
||||||
const tokenize = renderer === 'V3' ? tokenizeCustomMarkdown : legacyTokenizeCustomMarkdown;
|
const tokenize = renderer === 'V3' ? tokenizeCustomMarkdown : legacyTokenizeCustomMarkdown;
|
||||||
|
|
||||||
class countWidget extends WidgetType {
|
class countWidget extends WidgetType {
|
||||||
constructor(count) {
|
constructor(count) {
|
||||||
super();
|
super();
|
||||||
this.count = count;
|
this.count = count;
|
||||||
}
|
}
|
||||||
toDOM() {
|
toDOM() {
|
||||||
const span = document.createElement("span");
|
const span = document.createElement('span');
|
||||||
span.className = "cm-page-count";
|
span.className = 'cm-page-count';
|
||||||
span.textContent = this.count;
|
span.textContent = this.count;
|
||||||
span.style.color = "#989898";
|
span.style.color = '#989898';
|
||||||
return span;
|
return span;
|
||||||
}
|
}
|
||||||
ignoreEvent() { return true; }
|
ignoreEvent() { return true; }
|
||||||
}
|
}
|
||||||
|
|
||||||
return ViewPlugin.fromClass(
|
return ViewPlugin.fromClass(
|
||||||
class {
|
class {
|
||||||
@@ -154,6 +155,7 @@ const CodeEditor = forwardRef(
|
|||||||
highlightActiveLine(),
|
highlightActiveLine(),
|
||||||
highlightActiveLineGutter(),
|
highlightActiveLineGutter(),
|
||||||
highlightCompartment.of(combinedHighlight),
|
highlightCompartment.of(combinedHighlight),
|
||||||
|
autocompleteEmoji,
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
@import '@themes/codeMirror/customEditorStyles.less';
|
@import '@themes/codeMirror/customEditorStyles.less';
|
||||||
|
|
||||||
.editor {
|
.editor {
|
||||||
position : relative;
|
position : relative;
|
||||||
width : 100%;
|
width : 100%;
|
||||||
height : 100%;
|
height : 100%;
|
||||||
container : editor / inline-size;
|
container : editor / inline-size;
|
||||||
background:white;
|
background : white;
|
||||||
.codeEditor {
|
.codeEditor {
|
||||||
height : calc(100% - 25px);
|
height : calc(100% - 25px);
|
||||||
.cm-editor { height : 100%; }
|
.cm-editor { height : 100%; }
|
||||||
@@ -14,6 +14,20 @@
|
|||||||
background : #33333328;
|
background : #33333328;
|
||||||
border-top : #333399 solid 1px;
|
border-top : #333399 solid 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cm-tooltip-autocomplete {
|
||||||
|
|
||||||
|
li {
|
||||||
|
display : flex;
|
||||||
|
gap : 10px;
|
||||||
|
align-items : center;
|
||||||
|
justify-content : flex-start;
|
||||||
|
|
||||||
|
.cm-completionIcon { display : none; }
|
||||||
|
.cm-tooltip-autocomplete .cm-completionLabel { translate : 0 -2px; }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
.cm-page-count {
|
.cm-page-count {
|
||||||
float : right;
|
float : right;
|
||||||
|
|||||||
1
package-lock.json
generated
1
package-lock.json
generated
@@ -15,6 +15,7 @@
|
|||||||
"@babel/preset-env": "^7.29.0",
|
"@babel/preset-env": "^7.29.0",
|
||||||
"@babel/preset-react": "^7.28.5",
|
"@babel/preset-react": "^7.28.5",
|
||||||
"@babel/runtime": "^7.28.6",
|
"@babel/runtime": "^7.28.6",
|
||||||
|
"@codemirror/autocomplete": "^6.20.1",
|
||||||
"@codemirror/commands": "^6.10.3",
|
"@codemirror/commands": "^6.10.3",
|
||||||
"@codemirror/highlight": "^0.19.8",
|
"@codemirror/highlight": "^0.19.8",
|
||||||
"@codemirror/lang-css": "^6.3.1",
|
"@codemirror/lang-css": "^6.3.1",
|
||||||
|
|||||||
@@ -91,6 +91,7 @@
|
|||||||
"@babel/preset-env": "^7.29.0",
|
"@babel/preset-env": "^7.29.0",
|
||||||
"@babel/preset-react": "^7.28.5",
|
"@babel/preset-react": "^7.28.5",
|
||||||
"@babel/runtime": "^7.28.6",
|
"@babel/runtime": "^7.28.6",
|
||||||
|
"@codemirror/autocomplete": "^6.20.1",
|
||||||
"@codemirror/commands": "^6.10.3",
|
"@codemirror/commands": "^6.10.3",
|
||||||
"@codemirror/highlight": "^0.19.8",
|
"@codemirror/highlight": "^0.19.8",
|
||||||
"@codemirror/lang-css": "^6.3.1",
|
"@codemirror/lang-css": "^6.3.1",
|
||||||
|
|||||||
Reference in New Issue
Block a user