mirror of
https://github.com/CorentinTh/it-tools.git
synced 2025-04-24 00:36:14 -04:00
feat(emoji-picker) add lazy loading to improve initial load performance
This commit is contained in:
parent
0b1b98f93e
commit
eb54661949
2 changed files with 57 additions and 11 deletions
|
@ -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';
|
||||
|
@ -36,10 +37,36 @@ 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"
|
||||
|
@ -47,11 +74,12 @@ const { searchResult } = useFuzzySearch({
|
|||
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"
|
||||
|
@ -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>
|
||||
|
|
|
@ -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';
|
||||
|
||||
|
@ -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'),
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue