Commit 1b94ec93 authored by Phil Hughes's avatar Phil Hughes

Added frequently used emojis to new picker

Adds frequently used emoji section to the new picker
Also adds emojis to frequently used when clicking
emojis.

https://gitlab.com/gitlab-org/gitlab/-/issues/23607
parent 30b23ace
<script>
import { GlIntersectionObserver } from '@gitlab/ui';
import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
import { humanize } from '~/lib/utils/text_utility';
import EmojiGroup from './emoji_group.vue';
export default {
......@@ -25,7 +25,7 @@ export default {
},
computed: {
categoryTitle() {
return capitalizeFirstCharacter(this.category);
return humanize(this.category);
},
},
methods: {
......@@ -33,9 +33,6 @@ export default {
this.renderGroup = true;
this.$emit('appear', this.category);
},
categoryDissappeared() {
this.renderGroup = false;
},
},
};
</script>
......
<script>
import { GlIcon, GlDropdown, GlSearchBoxByType } from '@gitlab/ui';
import { findLastIndex } from 'lodash';
import VirtualList from 'vue-virtual-scroll-list';
import { CATEGORY_NAMES } from '~/emoji';
import { CATEGORY_ICON_MAP } from '../constants';
import Category from './category.vue';
import EmojiList from './emoji_list.vue';
import { getEmojiCategories } from './utils';
import { addToFrequentlyUsed, getEmojiCategories, hasFrequentlyUsedEmojis } from './utils';
export default {
components: {
......@@ -25,13 +26,16 @@ export default {
},
data() {
return {
currentCategory: null,
currentCategory: 0,
searchValue: '',
};
},
computed: {
categoryNames() {
return CATEGORY_NAMES.map((category) => ({
return CATEGORY_NAMES.filter((c) => {
if (c === 'frequently_used') return hasFrequentlyUsedEmojis();
return true;
}).map((category) => ({
name: category,
icon: CATEGORY_ICON_MAP[category],
}));
......@@ -50,6 +54,7 @@ export default {
selectEmoji(name) {
this.$emit('click', name);
this.$refs.dropdown.hide();
addToFrequentlyUsed(name);
},
getBoundaryElement() {
return document.querySelector('.content-wrapper') || 'scrollParent';
......@@ -58,6 +63,11 @@ export default {
this.$refs.virtualScoller.setScrollTop(0);
this.$refs.virtualScoller.forceRender();
},
async onScroll(event, { offset }) {
const categories = await getEmojiCategories();
this.currentCategory = findLastIndex(Object.values(categories), ({ top }) => offset >= top);
},
},
};
</script>
......@@ -86,10 +96,10 @@ export default {
class="gl-display-flex gl-mx-5 gl-border-b-solid gl-border-gray-100 gl-border-b-1"
>
<button
v-for="category in categoryNames"
v-for="(category, index) in categoryNames"
:key="category.name"
:class="{
'gl-text-black-normal! emoji-picker-category-active': category.name === currentCategory,
'gl-text-black-normal! emoji-picker-category-active': index === currentCategory,
}"
type="button"
class="gl-border-0 gl-border-b-2 gl-border-b-solid gl-flex-fill-1 gl-text-gray-300 gl-pt-3 gl-pb-3 gl-bg-transparent emoji-picker-category-tab"
......@@ -100,18 +110,20 @@ export default {
</div>
<emoji-list :search-value="searchValue">
<template #default="{ filteredCategories }">
<virtual-list ref="virtualScoller" :size="258" :remain="1" :bench="2" variable>
<virtual-list
ref="virtualScoller"
:size="258"
:remain="1"
:bench="2"
variable
:onscroll="onScroll"
>
<div
v-for="(category, categoryKey) in filteredCategories"
:key="categoryKey"
:style="{ height: category.height + 'px' }"
>
<category
:category="categoryKey"
:emojis="category.emojis"
@appear="categoryAppeared"
@click="selectEmoji"
/>
<category :category="categoryKey" :emojis="category.emojis" @click="selectEmoji" />
</div>
</virtual-list>
</template>
......
import { chunk, memoize } from 'lodash';
import Cookies from 'js-cookie';
import { chunk, memoize, uniq } from 'lodash';
import { initEmojiMap, getEmojiCategoryMap } from '~/emoji';
import { EMOJIS_PER_ROW, EMOJI_ROW_HEIGHT, CATEGORY_ROW_HEIGHT } from '../constants';
export const generateCategoryHeight = (emojisLength) =>
emojisLength * EMOJI_ROW_HEIGHT + CATEGORY_ROW_HEIGHT;
export const getFrequentlyUsedEmojis = () => {
const savedEmojis = Cookies.get('frequently_used_emojis');
if (!savedEmojis) return null;
const emojis = chunk(uniq(savedEmojis.split(',')), 9);
return {
frequently_used: {
emojis,
top: 0,
height: generateCategoryHeight(emojis.length),
},
};
};
export const addToFrequentlyUsed = (emoji) => {
const frequentlyUsedEmojis = uniq(
(Cookies.get('frequently_used_emojis') || '')
.split(',')
.filter((e) => e)
.concat(emoji),
);
Cookies.set('frequently_used_emojis', frequentlyUsedEmojis.join(','), { expires: 365 });
};
export const hasFrequentlyUsedEmojis = () => getFrequentlyUsedEmojis() !== null;
export const getEmojiCategories = memoize(async () => {
await initEmojiMap();
const categories = await getEmojiCategoryMap();
let top = 0;
const frequentlyUsedEmojis = getFrequentlyUsedEmojis();
let top = frequentlyUsedEmojis
? frequentlyUsedEmojis.frequently_used.top + frequentlyUsedEmojis.frequently_used.height
: 0;
return Object.freeze(
Object.keys(categories).reduce((acc, category) => {
const emojis = chunk(categories[category], EMOJIS_PER_ROW);
const height = generateCategoryHeight(emojis.length);
const newAcc = {
...acc,
[category]: { emojis, height, top },
};
top += height;
return newAcc;
}, {}),
Object.keys(categories)
.filter((c) => c !== 'frequently_used')
.reduce((acc, category) => {
const emojis = chunk(categories[category], EMOJIS_PER_ROW);
const height = generateCategoryHeight(emojis.length);
const newAcc = {
...acc,
[category]: { emojis, height, top },
};
top += height;
return newAcc;
}, frequentlyUsedEmojis || {}),
);
});
export const CATEGORY_ICON_MAP = {
frequently_used: 'history',
activity: 'dumbbell',
people: 'smiley',
nature: 'nature',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment