Skip to content

Commit 48a0757

Browse files
committed
feat(emoji-picker) add lazy loading to improve initial load performance
1 parent 0b1b98f commit 48a0757

File tree

1 file changed

+55
-9
lines changed

1 file changed

+55
-9
lines changed

src/tools/emoji-picker/emoji-picker.vue

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import emojiUnicodeData from 'unicode-emoji-json';
33
import emojiKeywords from 'emojilib';
44
import _ from 'lodash';
5+
import { IconChevronRight, IconSearch } from '@tabler/icons-vue';
56
import type { EmojiInfo } from './emoji.types';
67
import { useFuzzySearch } from '@/composable/fuzzySearch';
78
import useDebouncedRef from '@/composable/debouncedref';
@@ -36,22 +37,49 @@ const { searchResult } = useFuzzySearch({
3637
isCaseSensitive: false,
3738
},
3839
});
40+
41+
const emojisPerPage = 30; // Number of emojis to load per group initially
42+
43+
// Tracks how many emojis are shown per group and the collapsed state of each group
44+
const groupLoadLimits = ref(
45+
emojisGroups.reduce((acc, group) => {
46+
acc[group.group] = { limit: emojisPerPage, collapsed: false };
47+
return acc;
48+
}, {} as Record<string, { limit: number; collapsed: boolean }>),
49+
);
50+
51+
// Toggles the visibility of the emoji group
52+
function toggleGroup(group: string) {
53+
groupLoadLimits.value[group].collapsed = !groupLoadLimits.value[group].collapsed;
54+
};
55+
56+
// Loads more emojis incrementally
57+
function loadMoreEmojis(group: string) {
58+
groupLoadLimits.value[group].limit += emojisPerPage;
59+
};
60+
61+
// Loads all emojis in the group at once
62+
function loadAllEmojis(group: string) {
63+
groupLoadLimits.value[group].limit = emojisGroups.find(g => g.group === group)?.emojiInfos.length || 0;
64+
};
3965
</script>
4066

4167
<template>
4268
<div mx-auto max-w-2400px important:flex-1>
69+
<!-- Emoji Search Bar -->
4370
<div flex items-center gap-3>
4471
<c-input-text
4572
v-model:value="searchQuery"
4673
placeholder="Search emojis (e.g. 'smile')..."
4774
mx-auto max-w-600px
4875
>
4976
<template #prefix>
50-
<icon-mdi-search mr-6px color-black op-70 dark:color-white />
77+
<n-icon :component="IconSearch" mr-6px color-black op-70 dark:color-white />
5178
</template>
5279
</c-input-text>
5380
</div>
5481

82+
<!-- Emoji Search Results -->
5583
<div v-if="searchQuery.trim().length > 0">
5684
<div
5785
v-if="searchResult.length === 0"
@@ -71,16 +99,34 @@ const { searchResult } = useFuzzySearch({
7199
</div>
72100
</div>
73101

74-
<div
75-
v-for="{ group, emojiInfos } in emojisGroups"
76-
v-else
77-
:key="group"
78-
>
79-
<div mt-4 text-20px font-bold>
80-
{{ group }}
102+
<div v-for="{ group, emojiInfos } in emojisGroups" :key="group">
103+
<!-- Collapsible Group Header with Chevron Icons -->
104+
<div
105+
mt-4 text-20px font-bold
106+
style="cursor: pointer;"
107+
@click="toggleGroup(group)"
108+
>
109+
<n-icon
110+
:component="IconChevronRight"
111+
:class="{ 'rotate-0': groupLoadLimits[group].collapsed, 'rotate-90': !groupLoadLimits[group].collapsed }"
112+
mr-1 text-16px lh-1 op-50 transition
113+
/>
114+
<span>{{ group }}</span>
81115
</div>
82116

83-
<emoji-grid :emoji-infos="emojiInfos" />
117+
<!-- Emoji Grid, conditionally displayed based on collapse state -->
118+
<div v-show="!groupLoadLimits[group].collapsed">
119+
<emoji-grid :emoji-infos="emojiInfos.slice(0, groupLoadLimits[group].limit)" />
120+
121+
<div v-if="groupLoadLimits[group].limit < emojiInfos.length" style="display: flex; gap: 8px; margin-top: 8px; justify-content: center;">
122+
<c-button @click="loadMoreEmojis(group)">
123+
Load More
124+
</c-button>
125+
<c-button @click="loadAllEmojis(group)">
126+
Load All
127+
</c-button>
128+
</div>
129+
</div>
84130
</div>
85131
</div>
86132
</template>

0 commit comments

Comments
 (0)