Skip to content

Commit 64da99a

Browse files
committed
refac
1 parent 012ce95 commit 64da99a

2 files changed

Lines changed: 48 additions & 2 deletions

File tree

src/lib/components/common/EmojiPicker.svelte

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
import emojiGroups from '$lib/emoji-groups.json';
1212
import emojiShortCodes from '$lib/emoji-shortcodes.json';
1313
14+
import { settings } from '$lib/stores';
15+
import { updateUserSettings } from '$lib/apis/users';
16+
1417
const i18n = getContext('i18n');
1518
1619
export let onClose = () => {};
@@ -20,12 +23,37 @@
2023
export let user = null;
2124
export let selected = null;
2225
26+
const MAX_RECENT = 30;
27+
2328
let show = false;
2429
let emojis = emojiShortCodes;
2530
let search = '';
2631
let flattenedEmojis = [];
2732
let emojiRows = [];
2833
34+
let saveDebounceTimer: ReturnType<typeof setTimeout> | null = null;
35+
36+
$: recentEmojiNames = ($settings?.recentEmojis ?? [])
37+
.filter((name) => emojiShortCodes[name])
38+
.slice(0, MAX_RECENT);
39+
40+
function saveRecentEmoji(emojiName: string) {
41+
// Remove if already present, then prepend
42+
const updated = [emojiName, ...recentEmojiNames.filter((n) => n !== emojiName)].slice(
43+
0,
44+
MAX_RECENT
45+
);
46+
47+
// Update store immediately (reactive UI)
48+
settings.set({ ...$settings, recentEmojis: updated });
49+
50+
// Debounce backend save (avoid API spam on rapid picks)
51+
if (saveDebounceTimer) clearTimeout(saveDebounceTimer);
52+
saveDebounceTimer = setTimeout(async () => {
53+
await updateUserSettings(localStorage.token, { ui: { ...$settings, recentEmojis: updated } });
54+
}, 1000);
55+
}
56+
2957
// Reactive statement to filter the emojis based on search query
3058
$: {
3159
if (search) {
@@ -55,6 +83,22 @@
5583
// Flatten emoji groups and group them into rows of 8 for virtual scrolling
5684
$: {
5785
flattenedEmojis = [];
86+
87+
// Add "Recently Used" group first (only when not searching)
88+
if (!search && recentEmojiNames.length > 0) {
89+
flattenedEmojis.push({ type: 'group', label: $i18n.t('Recently Used') });
90+
flattenedEmojis.push(
91+
...recentEmojiNames.map((emoji) => ({
92+
type: 'emoji',
93+
name: emoji,
94+
shortCodes:
95+
typeof emojiShortCodes[emoji] === 'string'
96+
? [emojiShortCodes[emoji]]
97+
: emojiShortCodes[emoji]
98+
}))
99+
);
100+
}
101+
58102
Object.keys(emojiGroups).forEach((group) => {
59103
const groupEmojis = emojiGroups[group].filter((emoji) => emojis[emoji]);
60104
if (groupEmojis.length > 0) {
@@ -97,6 +141,7 @@
97141
// Handle emoji selection
98142
function selectEmoji(emoji) {
99143
const selectedCode = emoji.shortCodes[0];
144+
saveRecentEmoji(emoji.name);
100145
if (selected === selectedCode) {
101146
onSubmit(null);
102147
} else {
@@ -140,10 +185,10 @@
140185
{:else}
141186
<div class="w-full flex ml-0.5">
142187
<VirtualList rowHeight={ROW_HEIGHT} items={emojiRows} height={384} let:item>
143-
<div class="w-full">
188+
<div class="w-full mb-2.5">
144189
{#if item.length === 1 && item[0].type === 'group'}
145190
<!-- Render group header -->
146-
<div class="text-xs font-medium mb-2 text-gray-500 dark:text-gray-400">
191+
<div class="text-xs font-medium -mb-1 text-gray-500 dark:text-gray-400">
147192
{item[0].label}
148193
</div>
149194
{:else}

src/lib/stores/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ type Settings = {
219219
chatDirection?: 'LTR' | 'RTL' | 'auto';
220220
ctrlEnterToSend?: boolean;
221221
renderMarkdownInPreviews?: boolean;
222+
recentEmojis?: string[];
222223

223224
system?: string;
224225
seed?: number;

0 commit comments

Comments
 (0)