diff --git a/apps/matrix/apps/web/src/lib/components/chat/MessageInput.svelte b/apps/matrix/apps/web/src/lib/components/chat/MessageInput.svelte index 49f2fd117..988ca053a 100644 --- a/apps/matrix/apps/web/src/lib/components/chat/MessageInput.svelte +++ b/apps/matrix/apps/web/src/lib/components/chat/MessageInput.svelte @@ -47,106 +47,59 @@ // Emoji picker state let showEmojiPicker = $state(false); + const RECENT_EMOJIS_KEY = 'matrix_recent_emojis'; + const MAX_RECENT_EMOJIS = 16; // 2 rows of 8 + + // Load recent emojis from localStorage + function loadRecentEmojis(): string[] { + if (typeof localStorage === 'undefined') return []; + try { + const stored = localStorage.getItem(RECENT_EMOJIS_KEY); + return stored ? JSON.parse(stored) : []; + } catch { + return []; + } + } + + // Save recent emojis to localStorage + function saveRecentEmojis(emojis: string[]) { + if (typeof localStorage === 'undefined') return; + try { + localStorage.setItem(RECENT_EMOJIS_KEY, JSON.stringify(emojis)); + } catch { + // Ignore storage errors + } + } + + // Add emoji to recent list + function addToRecentEmojis(emoji: string) { + const recent = loadRecentEmojis(); + // Remove if already exists, then add to front + const filtered = recent.filter((e) => e !== emoji); + const updated = [emoji, ...filtered].slice(0, MAX_RECENT_EMOJIS); + saveRecentEmojis(updated); + recentEmojis = updated; + } + + let recentEmojis = $state([]); + + // Load recent emojis on mount (browser only) + $effect(() => { + recentEmojis = loadRecentEmojis(); + }); + const commonEmojis = [ // Smileys - '๐Ÿ˜€', - '๐Ÿ˜ƒ', - '๐Ÿ˜„', - '๐Ÿ˜', - '๐Ÿ˜…', - '๐Ÿ˜‚', - '๐Ÿคฃ', - '๐Ÿ˜Š', - '๐Ÿ˜‡', - '๐Ÿ™‚', - '๐Ÿ˜‰', - '๐Ÿ˜Œ', - '๐Ÿ˜', - '๐Ÿฅฐ', - '๐Ÿ˜˜', - '๐Ÿ˜—', - '๐Ÿ˜™', - '๐Ÿ˜š', - '๐Ÿ˜‹', - '๐Ÿ˜›', - '๐Ÿ˜œ', - '๐Ÿคช', - '๐Ÿ˜', - '๐Ÿค—', - '๐Ÿคญ', - '๐Ÿคซ', - '๐Ÿค”', - '๐Ÿค', - '๐Ÿคจ', - '๐Ÿ˜', - '๐Ÿ˜‘', - '๐Ÿ˜ถ', - '๐Ÿ˜', - '๐Ÿ˜’', - '๐Ÿ™„', - '๐Ÿ˜ฌ', - '๐Ÿ˜ฎ', - '๐Ÿคฏ', - '๐Ÿ˜ณ', - '๐Ÿฅบ', - '๐Ÿ˜ข', - '๐Ÿ˜ญ', - '๐Ÿ˜ค', - '๐Ÿ˜ ', - '๐Ÿ˜ก', - '๐Ÿคฌ', - '๐Ÿ˜ˆ', - '๐Ÿ‘ฟ', + '๐Ÿ˜€', '๐Ÿ˜ƒ', '๐Ÿ˜„', '๐Ÿ˜', '๐Ÿ˜…', '๐Ÿ˜‚', '๐Ÿคฃ', '๐Ÿ˜Š', '๐Ÿ˜‡', '๐Ÿ™‚', '๐Ÿ˜‰', '๐Ÿ˜Œ', + '๐Ÿ˜', '๐Ÿฅฐ', '๐Ÿ˜˜', '๐Ÿ˜—', '๐Ÿ˜™', '๐Ÿ˜š', '๐Ÿ˜‹', '๐Ÿ˜›', '๐Ÿ˜œ', '๐Ÿคช', '๐Ÿ˜', '๐Ÿค—', + '๐Ÿคญ', '๐Ÿคซ', '๐Ÿค”', '๐Ÿค', '๐Ÿคจ', '๐Ÿ˜', '๐Ÿ˜‘', '๐Ÿ˜ถ', '๐Ÿ˜', '๐Ÿ˜’', '๐Ÿ™„', '๐Ÿ˜ฌ', + '๐Ÿ˜ฎ', '๐Ÿคฏ', '๐Ÿ˜ณ', '๐Ÿฅบ', '๐Ÿ˜ข', '๐Ÿ˜ญ', '๐Ÿ˜ค', '๐Ÿ˜ ', '๐Ÿ˜ก', '๐Ÿคฌ', '๐Ÿ˜ˆ', '๐Ÿ‘ฟ', // Gestures - '๐Ÿ‘', - '๐Ÿ‘Ž', - '๐Ÿ‘Œ', - '๐ŸคŒ', - 'โœŒ๏ธ', - '๐Ÿคž', - '๐ŸคŸ', - '๐Ÿค˜', - '๐Ÿค™', - '๐Ÿ‘‹', - '๐Ÿ–๏ธ', - 'โœ‹', - '๐Ÿ‘', - '๐Ÿ™Œ', - '๐Ÿ‘', - '๐Ÿคฒ', - '๐Ÿ™', - '๐Ÿ’ช', - '๐Ÿฆพ', - 'โค๏ธ', - '๐Ÿงก', - '๐Ÿ’›', - '๐Ÿ’š', - '๐Ÿ’™', + '๐Ÿ‘', '๐Ÿ‘Ž', '๐Ÿ‘Œ', '๐ŸคŒ', 'โœŒ๏ธ', '๐Ÿคž', '๐ŸคŸ', '๐Ÿค˜', '๐Ÿค™', '๐Ÿ‘‹', '๐Ÿ–๏ธ', 'โœ‹', + '๐Ÿ‘', '๐Ÿ™Œ', '๐Ÿ‘', '๐Ÿคฒ', '๐Ÿ™', '๐Ÿ’ช', '๐Ÿฆพ', 'โค๏ธ', '๐Ÿงก', '๐Ÿ’›', '๐Ÿ’š', '๐Ÿ’™', // Objects & Symbols - '๐Ÿ”ฅ', - 'โœจ', - '๐Ÿ’ซ', - 'โญ', - '๐ŸŒŸ', - '๐Ÿ’ฏ', - '๐Ÿ’ข', - '๐Ÿ’ฅ', - '๐Ÿ’ฆ', - '๐Ÿ’จ', - '๐ŸŽ‰', - '๐ŸŽŠ', - '๐ŸŽ', - '๐Ÿ†', - '๐Ÿฅ‡', - '๐ŸŽฏ', - '๐Ÿ’ก', - '๐Ÿ“Œ', - '๐Ÿ“', - 'โœ…', - 'โŒ', - 'โš ๏ธ', - 'โ—', - 'โ“', + '๐Ÿ”ฅ', 'โœจ', '๐Ÿ’ซ', 'โญ', '๐ŸŒŸ', '๐Ÿ’ฏ', '๐Ÿ’ข', '๐Ÿ’ฅ', '๐Ÿ’ฆ', '๐Ÿ’จ', '๐ŸŽ‰', '๐ŸŽŠ', + '๐ŸŽ', '๐Ÿ†', '๐Ÿฅ‡', '๐ŸŽฏ', '๐Ÿ’ก', '๐Ÿ“Œ', '๐Ÿ“', 'โœ…', 'โŒ', 'โš ๏ธ', 'โ—', 'โ“', ]; function insertEmoji(emoji: string) { @@ -155,6 +108,9 @@ const after = message.slice(cursorPos); message = before + emoji + after; + // Add to recent emojis + addToRecentEmojis(emoji); + // Close picker and focus textarea showEmojiPicker = false; setTimeout(() => { @@ -696,8 +652,26 @@ >
+ + {#if recentEmojis.length > 0} +
+

Hรคufig benutzt

+
+ {#each recentEmojis as emoji} + + {/each} +
+
+
+ {/if} +
{#each commonEmojis as emoji}