Skip to content

Commit

Permalink
Merge pull request #263 from sunnydanu/feat(emoji-picker)-implement-l…
Browse files Browse the repository at this point in the history
…azy-loading-to-improve-initial-load-search-performance-and-user-experience-updates

feat(emoji-picker) implement lazy loading to improve initial load/search performance and user experience updates
  • Loading branch information
sunnydanu authored Oct 28, 2024
2 parents c95ac78 + e140ab2 commit 5f18ed0
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 11 deletions.
64 changes: 55 additions & 9 deletions src/tools/emoji-picker/emoji-picker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import emojiUnicodeData from 'unicode-emoji-json';
import emojiKeywords from 'emojilib';
import _ from 'lodash';
import { IconChevronRight, IconSearch } from '@tabler/icons-vue';
import type { EmojiInfo } from './emoji.types';
import { useFuzzySearch } from '@/composable/fuzzySearch';
import useDebouncedRef from '@/composable/debouncedref';
Expand Down Expand Up @@ -36,22 +37,49 @@ const { searchResult } = useFuzzySearch({
isCaseSensitive: false,
},
});
const emojisPerPage = 30; // Number of emojis to load per group initially
// Tracks how many emojis are shown per group and the collapsed state of each group
const groupLoadLimits = ref(
emojisGroups.reduce((acc, group) => {
acc[group.group] = { limit: emojisPerPage, collapsed: false };
return acc;
}, {} as Record<string, { limit: number; collapsed: boolean }>),
);
// Toggles the visibility of the emoji group
function toggleGroup(group: string) {
groupLoadLimits.value[group].collapsed = !groupLoadLimits.value[group].collapsed;
};
// Loads more emojis incrementally
function loadMoreEmojis(group: string) {
groupLoadLimits.value[group].limit += emojisPerPage;
};
// Loads all emojis in the group at once
function loadAllEmojis(group: string) {
groupLoadLimits.value[group].limit = emojisGroups.find(g => g.group === group)?.emojiInfos.length || 0;
};
</script>

<template>
<div mx-auto max-w-2400px important:flex-1>
<!-- Emoji Search Bar -->
<div flex items-center gap-3>
<c-input-text
v-model:value="searchQuery"
placeholder="Search emojis (e.g. 'smile')..."
mx-auto max-w-600px
>
<template #prefix>
<icon-mdi-search mr-6px color-black op-70 dark:color-white />
<n-icon :component="IconSearch" mr-6px color-black op-70 dark:color-white />
</template>
</c-input-text>
</div>

<!-- Emoji Search Results -->
<div v-if="searchQuery.trim().length > 0">
<div
v-if="searchResult.length === 0"
Expand All @@ -71,16 +99,34 @@ const { searchResult } = useFuzzySearch({
</div>
</div>

<div
v-for="{ group, emojiInfos } in emojisGroups"
v-else
:key="group"
>
<div mt-4 text-20px font-bold>
{{ group }}
<div v-for="{ group, emojiInfos } in emojisGroups" :key="group">
<!-- Collapsible Group Header with Chevron Icons -->
<div
mt-4 text-20px font-bold
style="cursor: pointer;"
@click="toggleGroup(group)"
>
<n-icon
:component="IconChevronRight"
:class="{ 'rotate-0': groupLoadLimits[group].collapsed, 'rotate-90': !groupLoadLimits[group].collapsed }"
mr-1 text-16px lh-1 op-50 transition
/>
<span>{{ group }}</span>
</div>

<emoji-grid :emoji-infos="emojiInfos" />
<!-- Emoji Grid, conditionally displayed based on collapse state -->
<div v-show="!groupLoadLimits[group].collapsed">
<emoji-grid :emoji-infos="emojiInfos.slice(0, groupLoadLimits[group].limit)" />

<div v-if="groupLoadLimits[group].limit < emojiInfos.length" style="display: flex; gap: 8px; margin-top: 8px; justify-content: center;">
<c-button @click="loadMoreEmojis(group)">
Load More
</c-button>
<c-button @click="loadAllEmojis(group)">
Load All
</c-button>
</div>
</div>
</div>
</div>
</template>
4 changes: 2 additions & 2 deletions src/tools/emoji-picker/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { MoodSmile } from '@vicons/tabler';
import { IconMoodSmile } from '@tabler/icons-vue';
import { defineTool } from '../tool';
import { translate } from '@/plugins/i18n.plugin';

Expand All @@ -8,6 +8,6 @@ export const tool = defineTool({
description: translate('tools.emoji-picker.description'),
keywords: ['emoji', 'picker', 'unicode', 'copy', 'paste'],
component: () => import('./emoji-picker.vue'),
icon: MoodSmile,
icon: IconMoodSmile,
createdAt: new Date('2023-08-07'),
});

0 comments on commit 5f18ed0

Please sign in to comment.