forked from FoundKeyGang/FoundKey
client: Sort emojis by query similarity in fuzzy picker (#156)
Co-authored-by: Chloe Kudryavtsev <code@toast.bunkerlabs.net> Co-authored-by: Michcio <public+git@meekchopp.es> Reviewed-on: FoundKeyGang/FoundKey#156 Changelog: Changed Co-authored-by: Michcio <michcio@noreply.akkoma> Co-committed-by: Michcio <michcio@noreply.akkoma>
This commit is contained in:
parent
d5b0100d31
commit
d8a8306603
3 changed files with 98 additions and 8 deletions
|
@ -60,6 +60,7 @@
|
||||||
"strict-event-emitter-types": "2.0.0",
|
"strict-event-emitter-types": "2.0.0",
|
||||||
"stringz": "2.1.0",
|
"stringz": "2.1.0",
|
||||||
"syuilo-password-strength": "0.0.1",
|
"syuilo-password-strength": "0.0.1",
|
||||||
|
"talisman": "^1.1.4",
|
||||||
"textarea-caret": "3.1.0",
|
"textarea-caret": "3.1.0",
|
||||||
"three": "0.142.0",
|
"three": "0.142.0",
|
||||||
"throttle-debounce": "5.0.0",
|
"throttle-debounce": "5.0.0",
|
||||||
|
|
|
@ -80,6 +80,7 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, computed, watch, onMounted } from 'vue';
|
import { ref, computed, watch, onMounted } from 'vue';
|
||||||
import * as foundkey from 'foundkey-js';
|
import * as foundkey from 'foundkey-js';
|
||||||
|
import { distance as rodistance } from 'talisman/metrics/ratcliff-obershelp';
|
||||||
import XSection from './emoji-picker.section.vue';
|
import XSection from './emoji-picker.section.vue';
|
||||||
import { emojilist, UnicodeEmojiDef, unicodeEmojiCategories as categories } from '@/scripts/emojilist';
|
import { emojilist, UnicodeEmojiDef, unicodeEmojiCategories as categories } from '@/scripts/emojilist';
|
||||||
import { getStaticImageUrl } from '@/scripts/get-static-image-url';
|
import { getStaticImageUrl } from '@/scripts/get-static-image-url';
|
||||||
|
@ -128,16 +129,34 @@ const searchResultCustom = ref<foundkey.entities.CustomEmoji[]>([]);
|
||||||
const searchResultUnicode = ref<UnicodeEmojiDef[]>([]);
|
const searchResultUnicode = ref<UnicodeEmojiDef[]>([]);
|
||||||
const tab = ref<'index' | 'custom' | 'unicode' | 'tags'>('index');
|
const tab = ref<'index' | 'custom' | 'unicode' | 'tags'>('index');
|
||||||
|
|
||||||
function emojiSearch<Type>(src: Type[], max: number, query: string): Type[] {
|
function emojiSearch<Type extends foundkey.entities.CustomEmoji|UnicodeEmojiDef>(src: Type[], max: number, query: string): Type[] {
|
||||||
// discount fuzzy matching pattern
|
// discount fuzzy matching pattern
|
||||||
const re = new RegExp(query.split(' ').join('.*'), 'i');
|
const re = new RegExp(query.split(' ').join('.*'), 'i');
|
||||||
const match = (str: string): boolean => str && re.test(str);
|
const match = (str: string): boolean => !!str && re.test(str);
|
||||||
const matches = src.filter(emoji =>
|
const aliases = (emoji: Type): string[] => {
|
||||||
match(emoji.name)
|
// Custom and Unicode emojis have different fields
|
||||||
|| emoji.aliases?.some(match) // custom emoji
|
if ('aliases' in emoji) {
|
||||||
|| emoji.keywords?.some(match), // unicode emoji
|
return emoji.aliases;
|
||||||
);
|
}
|
||||||
// TODO: sort matches by distance to query
|
if ('keywords' in emoji) {
|
||||||
|
return emoji.keywords;
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
};
|
||||||
|
const matches = src.filter(emoji => match(emoji.name) || aliases(emoji).some(match));
|
||||||
|
|
||||||
|
// precompute distances
|
||||||
|
const distances = {};
|
||||||
|
const joinq = query.replace(/\s+/g, '');
|
||||||
|
const distance = (str: string): number => rodistance(joinq, str);
|
||||||
|
const mindistance = (strs: string[]): number => Math.min(...strs.map(distance));
|
||||||
|
const distinguisher = (emoji: Type): string => 'char' in emoji ? emoji.char : emoji.id;
|
||||||
|
for (const emoji of matches) {
|
||||||
|
distances[distinguisher(emoji)] = Math.min(distance(emoji.name), mindistance(aliases(emoji)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort by distance from query
|
||||||
|
matches.sort((a, b) => distances[distinguisher(a)] - distances[distinguisher(b)]);
|
||||||
if (max <= 0 || matches.length < max) return matches;
|
if (max <= 0 || matches.length < max) return matches;
|
||||||
return matches.slice(0, max);
|
return matches.slice(0, max);
|
||||||
}
|
}
|
||||||
|
|
70
yarn.lock
70
yarn.lock
|
@ -4742,6 +4742,7 @@ __metadata:
|
||||||
strict-event-emitter-types: 2.0.0
|
strict-event-emitter-types: 2.0.0
|
||||||
stringz: 2.1.0
|
stringz: 2.1.0
|
||||||
syuilo-password-strength: 0.0.1
|
syuilo-password-strength: 0.0.1
|
||||||
|
talisman: ^1.1.4
|
||||||
textarea-caret: 3.1.0
|
textarea-caret: 3.1.0
|
||||||
three: 0.142.0
|
three: 0.142.0
|
||||||
throttle-debounce: 5.0.0
|
throttle-debounce: 5.0.0
|
||||||
|
@ -8773,6 +8774,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"html-entities@npm:^1.4.0":
|
||||||
|
version: 1.4.0
|
||||||
|
resolution: "html-entities@npm:1.4.0"
|
||||||
|
checksum: 4b73ffb9eead200f99146e4fbe70acb0af2fea136901a131fc3a782e9ef876a7cbb07dec303ca1f8804232b812249dbf3643a270c9c524852065d9224a8dcdd0
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"html-escaper@npm:^2.0.0":
|
"html-escaper@npm:^2.0.0":
|
||||||
version: 2.0.2
|
version: 2.0.2
|
||||||
resolution: "html-escaper@npm:2.0.2"
|
resolution: "html-escaper@npm:2.0.2"
|
||||||
|
@ -11447,6 +11455,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"long@npm:^4.0.0":
|
||||||
|
version: 4.0.0
|
||||||
|
resolution: "long@npm:4.0.0"
|
||||||
|
checksum: 16afbe8f749c7c849db1f4de4e2e6a31ac6e617cead3bdc4f9605cb703cd20e1e9fc1a7baba674ffcca57d660a6e5b53a9e236d7b25a295d3855cca79cc06744
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"lowercase-keys@npm:^2.0.0":
|
"lowercase-keys@npm:^2.0.0":
|
||||||
version: 2.0.0
|
version: 2.0.0
|
||||||
resolution: "lowercase-keys@npm:2.0.0"
|
resolution: "lowercase-keys@npm:2.0.0"
|
||||||
|
@ -11986,6 +12001,24 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"mnemonist@npm:^0.38.1":
|
||||||
|
version: 0.38.5
|
||||||
|
resolution: "mnemonist@npm:0.38.5"
|
||||||
|
dependencies:
|
||||||
|
obliterator: ^2.0.0
|
||||||
|
checksum: 66080afc1616866beb164e230c432964d6eed467cf37ad00e9c10161b8267928124ca8f1d0ecfea86c85568acfa62d54faaf646a86968d1135189a0fdfdd6b78
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"mnemonist@npm:^0.39.0":
|
||||||
|
version: 0.39.2
|
||||||
|
resolution: "mnemonist@npm:0.39.2"
|
||||||
|
dependencies:
|
||||||
|
obliterator: ^2.0.1
|
||||||
|
checksum: 77075ddf30c5e7ee8ccde6d09b61a2511eb324e9d04871e6cb48ede9ed1d2b002ad121314912bf1926d12ba3cb520ca2fb54c2a6c3f9d4467774af2f447907aa
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"mocha@npm:10.0.0":
|
"mocha@npm:10.0.0":
|
||||||
version: 10.0.0
|
version: 10.0.0
|
||||||
resolution: "mocha@npm:10.0.0"
|
resolution: "mocha@npm:10.0.0"
|
||||||
|
@ -12679,6 +12712,20 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"obliterator@npm:^1.6.1":
|
||||||
|
version: 1.6.1
|
||||||
|
resolution: "obliterator@npm:1.6.1"
|
||||||
|
checksum: 12412ce97bc9680a50ec1e865c9f106f924497f0b73c01947031079da7c9a0f5212f3a1aeea3227f7771ed4a273e42b2a2e6ff93578301c8117dbb3135770133
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"obliterator@npm:^2.0.0, obliterator@npm:^2.0.1":
|
||||||
|
version: 2.0.4
|
||||||
|
resolution: "obliterator@npm:2.0.4"
|
||||||
|
checksum: f28ad35b6d812089315f375dc3e6e5f9bebf958ebe4b10ccd471c7115cbcf595e74bdac4783ae758e5b1f47e3096427fdb37cfa7bed566b132df92ff317b9a7c
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"oblivious-set@npm:1.1.1":
|
"oblivious-set@npm:1.1.1":
|
||||||
version: 1.1.1
|
version: 1.1.1
|
||||||
resolution: "oblivious-set@npm:1.1.1"
|
resolution: "oblivious-set@npm:1.1.1"
|
||||||
|
@ -12904,6 +12951,15 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"pandemonium@npm:^2.0.0":
|
||||||
|
version: 2.3.0
|
||||||
|
resolution: "pandemonium@npm:2.3.0"
|
||||||
|
dependencies:
|
||||||
|
mnemonist: ^0.39.0
|
||||||
|
checksum: 0353f9e03ea1981189291f103ad11d886b347cdafc09631010df4e8616966b6d4854c8f658b5a4a72eae7857b31351a1cf88034ed1f948ba63905eaba5a0ad01
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"parent-module@npm:^1.0.0":
|
"parent-module@npm:^1.0.0":
|
||||||
version: 1.0.1
|
version: 1.0.1
|
||||||
resolution: "parent-module@npm:1.0.1"
|
resolution: "parent-module@npm:1.0.1"
|
||||||
|
@ -16093,6 +16149,20 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"talisman@npm:^1.1.4":
|
||||||
|
version: 1.1.4
|
||||||
|
resolution: "talisman@npm:1.1.4"
|
||||||
|
dependencies:
|
||||||
|
html-entities: ^1.4.0
|
||||||
|
lodash: ^4.17.20
|
||||||
|
long: ^4.0.0
|
||||||
|
mnemonist: ^0.38.1
|
||||||
|
obliterator: ^1.6.1
|
||||||
|
pandemonium: ^2.0.0
|
||||||
|
checksum: aa94150df065f16e9cf6d153413e48317f4fd64332b6f5c17f43c49af86b141ebdb2b111c8f1b0bb04e6dd7acab9b451d8822c26739f69afba562c73a010444c
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"tapable@npm:^2.2.0":
|
"tapable@npm:^2.2.0":
|
||||||
version: 2.2.1
|
version: 2.2.1
|
||||||
resolution: "tapable@npm:2.2.1"
|
resolution: "tapable@npm:2.2.1"
|
||||||
|
|
Loading…
Reference in a new issue