mirror of
https://github.com/marsbatya/tg-emoji-search.git
synced 2026-07-22 05:41:44 +00:00
add the feature of adding custom mappings
This commit is contained in:
parent
f9e834eb0f
commit
107e4b2c26
3 changed files with 211 additions and 23 deletions
|
|
@ -20,7 +20,11 @@ This plugin provides a fast and intuitive way to insert emojis into your Obsidia
|
|||
- The core emoji search is implemented in Rust, compiled to WebAssembly for speed.
|
||||
- TypeScript provides type safety and works seamlessly with the Obsidian plugin API.
|
||||
|
||||
4. **Customizable Settings**
|
||||
4. **Custom emoji mappings**
|
||||
- Feel free to add or delete your own keyword, when you're not satisfied with existing ones
|
||||
- You can also reset these mappings easily
|
||||
|
||||
5. **Customizable Settings**
|
||||
- **Default Language**: Choose which language’s keywords to use.
|
||||
- **Trigger Character**: Change the character that initiates the emoji search (default is `:`).
|
||||
- **Show Keywords in Suggestions**: Toggle the display of each emoji’s keyword in the suggestion list.
|
||||
|
|
|
|||
125
main.ts
125
main.ts
|
|
@ -32,13 +32,15 @@ interface EmojiSuggesterPluginSettings {
|
|||
triggerChar: string;
|
||||
showKeywords: boolean;
|
||||
emojiPopularity: Record<string, number>;
|
||||
customEmojiMappings: Record<string, string>;
|
||||
}
|
||||
|
||||
const DEFAULT_SETTINGS: EmojiSuggesterPluginSettings = {
|
||||
defaultLanguage: 'english',
|
||||
triggerChar: ':',
|
||||
showKeywords: true, // default to showing keywords
|
||||
emojiPopularity: {}, // empty ranking
|
||||
showKeywords: true,
|
||||
emojiPopularity: {},
|
||||
customEmojiMappings: {},
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -154,7 +156,6 @@ class EmojiSuggester extends EditorSuggest<string> {
|
|||
query: match[1]?.trim() || ''
|
||||
};
|
||||
}
|
||||
|
||||
getSuggestions(context: EditorSuggestContext): string[] {
|
||||
if (!context.query || !this.emojiSearch) return [];
|
||||
const language = /[а-яА-Я]/.test(context.query)
|
||||
|
|
@ -162,8 +163,11 @@ class EmojiSuggester extends EditorSuggest<string> {
|
|||
: this.settings.defaultLanguage;
|
||||
|
||||
try {
|
||||
// Get results from the WASM module
|
||||
const results: [string, string[]][] = JSON.parse(this.emojiSearch.search(context.query, language));
|
||||
const emojiMap = new Map<string, string>();
|
||||
|
||||
// Add emojis from WASM search results
|
||||
for (const [keyword, emojis] of results) {
|
||||
for (const emoji of emojis) {
|
||||
if (!emojiMap.has(emoji)) {
|
||||
|
|
@ -172,12 +176,21 @@ class EmojiSuggester extends EditorSuggest<string> {
|
|||
}
|
||||
}
|
||||
|
||||
// Add custom emoji mappings that match the query
|
||||
const query = context.query.toLowerCase();
|
||||
for (const [keyword, emoji] of Object.entries(this.plugin.settings.customEmojiMappings)) {
|
||||
if (keyword.toLowerCase().includes(query)) {
|
||||
emojiMap.set(emoji, keyword);
|
||||
}
|
||||
}
|
||||
|
||||
const emojisWithKeywords = Array.from(emojiMap.entries());
|
||||
|
||||
// Sort by popularity
|
||||
emojisWithKeywords.sort((a, b) => {
|
||||
const popA = this.plugin.settings.emojiPopularity[a[0]] || 0;
|
||||
const popB = this.plugin.settings.emojiPopularity[b[0]] || 0;
|
||||
return popB - popA; // Sort in descending order
|
||||
return popB - popA;
|
||||
});
|
||||
|
||||
if (this.settings.showKeywords) {
|
||||
|
|
@ -192,7 +205,6 @@ class EmojiSuggester extends EditorSuggest<string> {
|
|||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
renderSuggestion(value: string, el: HTMLElement): void {
|
||||
el.empty();
|
||||
if (this.settings.showKeywords) {
|
||||
|
|
@ -257,7 +269,7 @@ class EmojiSuggesterSettingTab extends PluginSettingTab {
|
|||
display(): void {
|
||||
const { containerEl } = this;
|
||||
containerEl.empty();
|
||||
containerEl.createEl('h2', { text: 'Emoji Suggester Settings' });
|
||||
containerEl.createEl('h2', { text: 'Advanced' });
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Default Language')
|
||||
|
|
@ -292,6 +304,64 @@ class EmojiSuggesterSettingTab extends PluginSettingTab {
|
|||
this.plugin.settings.showKeywords = value;
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
// Add section for custom emoji mappings
|
||||
containerEl.createEl('h2', { text: 'Custom Emoji Mappings' });
|
||||
|
||||
// Display existing custom mappings
|
||||
const customMappingsContainer = containerEl.createDiv('custom-emoji-mappings-container');
|
||||
this.renderCustomMappings(customMappingsContainer);
|
||||
|
||||
// Add new mapping controls
|
||||
const newMappingContainer = containerEl.createDiv('new-emoji-mapping-container');
|
||||
|
||||
const keywordInput = newMappingContainer.createEl('input');
|
||||
keywordInput.type = 'text';
|
||||
keywordInput.placeholder = 'Keyword';
|
||||
keywordInput.classList.add('custom-emoji-keyword-input');
|
||||
|
||||
const emojiInput = newMappingContainer.createEl('input');
|
||||
emojiInput.type = 'text';
|
||||
emojiInput.placeholder = 'Emoji';
|
||||
emojiInput.classList.add('custom-emoji-input');
|
||||
|
||||
const addButton = newMappingContainer.createEl('button');
|
||||
addButton.setText('Add');
|
||||
addButton.classList.add('custom-emoji-add-button');
|
||||
addButton.addEventListener('click', async () => {
|
||||
const keyword = keywordInput.value.trim();
|
||||
const emoji = emojiInput.value.trim();
|
||||
|
||||
if (keyword && emoji) {
|
||||
this.plugin.settings.customEmojiMappings[keyword] = emoji;
|
||||
await this.plugin.saveSettings();
|
||||
|
||||
// Clear inputs
|
||||
keywordInput.value = '';
|
||||
emojiInput.value = '';
|
||||
|
||||
// Refresh the mappings display
|
||||
this.renderCustomMappings(customMappingsContainer);
|
||||
new Notice(`Added custom mapping: ${keyword} → ${emoji}`);
|
||||
} else {
|
||||
new Notice('Both keyword and emoji are required');
|
||||
}
|
||||
});
|
||||
|
||||
// Reset Custom Mappings button
|
||||
new Setting(containerEl)
|
||||
.setName('Reset Custom Emoji Mappings')
|
||||
.setDesc('Remove all your custom emoji mappings')
|
||||
.addButton(button => button
|
||||
.setButtonText('Reset')
|
||||
.onClick(async () => {
|
||||
this.plugin.settings.customEmojiMappings = {};
|
||||
await this.plugin.saveSettings();
|
||||
this.renderCustomMappings(customMappingsContainer);
|
||||
new Notice('Custom emoji mappings have been reset');
|
||||
}));
|
||||
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Reset Emoji Popularity')
|
||||
.setDesc('Reset your emoji usage statistics')
|
||||
|
|
@ -313,7 +383,7 @@ class EmojiSuggesterSettingTab extends PluginSettingTab {
|
|||
// Display top 10 most used emojis
|
||||
const topEmojisEl = containerEl.createDiv();
|
||||
topEmojisEl.addClass('emoji-popularity-stats');
|
||||
topEmojisEl.createEl('h3', { text: 'Your Most Used Emojis' });
|
||||
topEmojisEl.createEl('h2', { text: 'Your Most Used Emojis' });
|
||||
|
||||
const popularityEntries = Object.entries(this.plugin.settings.emojiPopularity);
|
||||
popularityEntries.sort((a, b) => b[1] - a[1]);
|
||||
|
|
@ -338,6 +408,47 @@ class EmojiSuggesterSettingTab extends PluginSettingTab {
|
|||
countSpan.addClass('emoji-top-count');
|
||||
countSpan.textContent = `Used ${count} time${count !== 1 ? 's' : ''}`;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
private renderCustomMappings(containerEl: HTMLElement): void {
|
||||
containerEl.empty();
|
||||
|
||||
const mappings = this.plugin.settings.customEmojiMappings;
|
||||
const entries = Object.entries(mappings);
|
||||
|
||||
if (entries.length === 0) {
|
||||
containerEl.createEl('p', { text: 'No custom emoji mappings yet' });
|
||||
return;
|
||||
}
|
||||
|
||||
const table = containerEl.createEl('table');
|
||||
table.classList.add('custom-emoji-table');
|
||||
|
||||
// Create header row
|
||||
const headerRow = table.createEl('tr');
|
||||
headerRow.createEl('th', { text: 'Keyword' });
|
||||
headerRow.createEl('th', { text: 'Emoji' });
|
||||
headerRow.createEl('th', { text: 'Action' });
|
||||
|
||||
// Create rows for each mapping
|
||||
for (const [keyword, emoji] of entries) {
|
||||
const row = table.createEl('tr');
|
||||
row.createEl('td', { text: keyword });
|
||||
row.createEl('td', { text: emoji });
|
||||
|
||||
const actionCell = row.createEl('td');
|
||||
const deleteButton = actionCell.createEl('button');
|
||||
deleteButton.setText('Delete');
|
||||
deleteButton.classList.add('custom-emoji-delete-button');
|
||||
deleteButton.addEventListener('click', async () => {
|
||||
delete this.plugin.settings.customEmojiMappings[keyword];
|
||||
await this.plugin.saveSettings();
|
||||
this.renderCustomMappings(containerEl);
|
||||
new Notice(`Removed custom mapping: ${keyword}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
103
styles.css
103
styles.css
|
|
@ -1,43 +1,116 @@
|
|||
/* Emoji Suggester Plugin Styles */
|
||||
|
||||
/* Suggestion items styling */
|
||||
/* Common variables */
|
||||
:root {
|
||||
--emoji-font-size: 1.5em;
|
||||
--emoji-margin-right: 0.625rem;
|
||||
--standard-spacing: 0.625rem;
|
||||
--container-margin: 1rem;
|
||||
--border-color: var(--background-modifier-border);
|
||||
}
|
||||
|
||||
/* === Suggestion Popup Styles === */
|
||||
.emoji-suggestion-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0.25rem 0;
|
||||
}
|
||||
|
||||
.emoji-suggestion-emoji {
|
||||
font-size: 1.5em;
|
||||
margin-right: 10px;
|
||||
font-size: var(--emoji-font-size);
|
||||
margin-right: var(--emoji-margin-right);
|
||||
}
|
||||
|
||||
.emoji-suggestion-emoji:only-child {
|
||||
margin: 0 var(--standard-spacing);
|
||||
}
|
||||
|
||||
.emoji-suggestion-keyword {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
/* Settings tab styling */
|
||||
/* === Settings Tab Styles === */
|
||||
|
||||
|
||||
/* Custom Emoji Mappings Section */
|
||||
.custom-emoji-mappings-container {
|
||||
margin-bottom: var(--container-margin);
|
||||
max-height: 12.5rem;
|
||||
overflow-y: auto;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
|
||||
.custom-emoji-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.custom-emoji-table th,
|
||||
.custom-emoji-table td {
|
||||
padding: 0.5rem;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
/* New Emoji Mapping Controls */
|
||||
.new-emoji-mapping-container {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: var(--container-margin);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.custom-emoji-keyword-input,
|
||||
.custom-emoji-input {
|
||||
flex: 1;
|
||||
padding: 0.5rem;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
|
||||
.custom-emoji-add-button,
|
||||
.custom-emoji-delete-button {
|
||||
padding: 0.4rem 0.6rem;
|
||||
cursor: pointer;
|
||||
background-color: var(--interactive-accent);
|
||||
color: var(--text-on-accent);
|
||||
border: none;
|
||||
border-radius: 0.25rem;
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
|
||||
.custom-emoji-add-button:hover,
|
||||
.custom-emoji-delete-button:hover {
|
||||
background-color: var(--interactive-accent-hover);
|
||||
}
|
||||
|
||||
.custom-emoji-delete-button {
|
||||
background-color: var(--text-error);
|
||||
}
|
||||
|
||||
.custom-emoji-delete-button:hover {
|
||||
background-color: var(--text-error-hover);
|
||||
}
|
||||
|
||||
/* Emoji Popularity Section */
|
||||
.emoji-popularity-stats {
|
||||
margin-top: 20px;
|
||||
margin-top: var(--container-margin);
|
||||
}
|
||||
|
||||
.emoji-top-list {
|
||||
margin-top: 10px;
|
||||
margin-top: var(--standard-spacing);
|
||||
}
|
||||
|
||||
.emoji-top-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 5px 0;
|
||||
padding: 0.3125rem 0;
|
||||
}
|
||||
|
||||
.emoji-top-symbol {
|
||||
font-size: 1.5em;
|
||||
margin-right: 10px;
|
||||
min-width: 40px;
|
||||
font-size: var(--emoji-font-size);
|
||||
margin-right: var(--emoji-margin-right);
|
||||
min-width: 2.5rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* When showing only emoji without keywords */
|
||||
.emoji-suggestion-emoji:only-child {
|
||||
margin: 0 10px;
|
||||
}
|
||||
Loading…
Reference in a new issue