mirror of
https://github.com/hcengineering/platform.git
synced 2025-05-10 17:30:51 +00:00
Extend emojis with Custom type
Signed-off-by: Anton Alexeyev <alexeyev.anton@gmail.com>
This commit is contained in:
parent
7df8a2c779
commit
c8f61385ec
@ -5,34 +5,34 @@
|
||||
//
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import type { Emoji } from 'emojibase'
|
||||
import { EmojiWithGroup, getEmojiByHexcode } from '.'
|
||||
import { EmojiButton, getSkinTone, emojiStore } from '.'
|
||||
import { ExtendedEmoji, getEmojiByHexcode, EmojiButton, getSkinTone, emojiStore, getEmojiSkins } from '.'
|
||||
import { Label, IconDelete, closeTooltip, ButtonBase } from '../..'
|
||||
import plugin from '../../plugin'
|
||||
import SkinToneTooltip from './SkinToneTooltip.svelte'
|
||||
|
||||
export let emoji: EmojiWithGroup
|
||||
export let emoji: ExtendedEmoji
|
||||
export let remove: boolean = false
|
||||
export let skinTone: number = getSkinTone()
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
closeTooltip()
|
||||
|
||||
const haveSkins = Array.isArray(emoji.skins)
|
||||
const combinedEmoji = haveSkins && (emoji?.skins?.length ?? 0) > 5
|
||||
const skins = getEmojiSkins(emoji)
|
||||
const haveSkins = Array.isArray(skins)
|
||||
const combinedEmoji = haveSkins && (skins?.length ?? 0) > 5
|
||||
|
||||
const clickRemove = (): void => {
|
||||
dispatch('close', 'remove')
|
||||
}
|
||||
const getEmojiParts = (e: EmojiWithGroup): EmojiWithGroup[] => {
|
||||
const getEmojiParts = (): ExtendedEmoji[] => {
|
||||
const def = $emojiStore[168]
|
||||
const temp = e.skins?.find((skin) => Array.isArray(skin.tone) && skin.tone.length > 1)?.hexcode.split('-200D-')
|
||||
const temp = skins?.find((skin) => Array.isArray(skin.tone) && skin.tone.length > 1)?.hexcode.split('-200D-')
|
||||
if (temp === undefined || temp.length < 2) return [def, def]
|
||||
const firstEmoji = getEmojiByHexcode(temp[0].slice(0, -6)) ?? def
|
||||
const secondEmoji = getEmojiByHexcode(temp[temp.length - 1].slice(0, -6)) ?? def
|
||||
return [firstEmoji, secondEmoji]
|
||||
}
|
||||
const emojiParts = getEmojiParts(emoji)
|
||||
const emojiParts = getEmojiParts()
|
||||
const combinedTones: number[] = [skinTone, skinTone]
|
||||
|
||||
const updateSkinTone = (result: CustomEvent<{ detail: number }>, index: number): void => {
|
||||
@ -45,16 +45,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
const getEmojiByTone = (e: EmojiWithGroup, [a, b]: number[]): Emoji | undefined => {
|
||||
const getEmojiByTone = (e: ExtendedEmoji, [a, b]: number[]): Emoji | undefined => {
|
||||
const equal = a === b
|
||||
const noTone = a === 0
|
||||
return equal && noTone
|
||||
? e
|
||||
: e.skins?.find((skin) =>
|
||||
? e as Emoji
|
||||
: getEmojiSkins(e)?.find((skin) =>
|
||||
equal ? skin.tone === a : Array.isArray(skin.tone) && skin.tone[0] === a && skin.tone[1] === b
|
||||
)
|
||||
}
|
||||
const getEmojiStringByTone = (e: EmojiWithGroup, [a, b]: number[]): string | undefined => {
|
||||
const getEmojiStringByTone = (e: ExtendedEmoji, [a, b]: number[]): string | undefined => {
|
||||
return getEmojiByTone(e, [a, b])?.emoji
|
||||
}
|
||||
</script>
|
||||
@ -92,7 +92,7 @@
|
||||
</div>
|
||||
{:else}
|
||||
<div class="hulyPopup-row disabled skins-row">
|
||||
{#each new Array((emoji.skins?.length ?? 5) + 1) as _, skin}
|
||||
{#each new Array((skins?.length ?? 5) + 1) as _, skin}
|
||||
<EmojiButton {emoji} skinTone={skin} preview on:select={(result) => dispatch('close', result.detail)} />
|
||||
{/each}
|
||||
</div>
|
||||
|
@ -5,25 +5,23 @@
|
||||
//
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { getEmbeddedLabel } from '@hcengineering/platform'
|
||||
import { tooltip, capitalizeFirstLetter, type EmojiWithGroup, type LabelAndProps } from '../../'
|
||||
import { type Emoji } from 'emojibase'
|
||||
import { tooltip, capitalizeFirstLetter, type LabelAndProps, type ExtendedEmoji, getEmojiSkins } from '../../'
|
||||
import { isCustomEmoji } from './types'
|
||||
|
||||
export let emoji: EmojiWithGroup
|
||||
export let emoji: ExtendedEmoji
|
||||
export let selected: boolean = false
|
||||
export let disabled: boolean = false
|
||||
export let preview: boolean = false
|
||||
export let skinTone: number = 0
|
||||
export let showTooltip: LabelAndProps | undefined = undefined
|
||||
|
||||
const skins = getEmojiSkins(emoji)
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
const getSkinsCount = (e: EmojiWithGroup): number | undefined => {
|
||||
return Array.isArray(e.skins) ? e.skins.length : undefined
|
||||
}
|
||||
|
||||
let displayedEmoji: Emoji | EmojiWithGroup
|
||||
$: skinIndex = emoji?.skins?.findIndex((skin) => skin.tone === skinTone) ?? -1
|
||||
$: displayedEmoji = skinTone > 0 && Array.isArray(emoji.skins) && skinIndex > -1 ? emoji.skins[skinIndex] : emoji
|
||||
let displayedEmoji: ExtendedEmoji
|
||||
$: skinIndex = skins?.findIndex((skin) => skin.tone === skinTone) ?? -1
|
||||
$: displayedEmoji = skinTone > 0 && skins !== undefined && skinIndex > -1 ? skins[skinIndex] : emoji
|
||||
</script>
|
||||
|
||||
{#if emoji}
|
||||
@ -32,9 +30,9 @@
|
||||
class="hulyPopupEmoji-button"
|
||||
class:preview
|
||||
class:selected
|
||||
class:skins={emoji?.skins !== undefined && emoji.skins.length === 5}
|
||||
class:constructor={emoji?.skins !== undefined && emoji.skins.length > 5}
|
||||
data-skins={getSkinsCount(emoji)}
|
||||
class:skins={skins !== undefined && skins.length === 5}
|
||||
class:constructor={skins !== undefined && skins.length > 5}
|
||||
data-skins={skins?.length}
|
||||
{disabled}
|
||||
on:touchstart
|
||||
on:contextmenu
|
||||
@ -43,7 +41,7 @@
|
||||
dispatch('select', displayedEmoji)
|
||||
}}
|
||||
>
|
||||
<span>{displayedEmoji.emoji}</span>
|
||||
<span>{isCustomEmoji(displayedEmoji) ? displayedEmoji.shortcode : displayedEmoji.emoji}</span>
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
|
@ -15,11 +15,12 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import type { EmojiWithGroup } from '.'
|
||||
import type { ExtendedEmoji } from '.'
|
||||
|
||||
import EmojiButton from './EmojiButton.svelte'
|
||||
import { isCustomEmoji } from './types'
|
||||
|
||||
export let emojis: EmojiWithGroup[]
|
||||
export let emojis: ExtendedEmoji[]
|
||||
export let selected: string | undefined
|
||||
export let disabled: boolean = false
|
||||
export let skinTone: number = 0
|
||||
@ -31,7 +32,7 @@
|
||||
{#each emojis as emoji}
|
||||
<EmojiButton
|
||||
{emoji}
|
||||
selected={emoji.emoji === selected}
|
||||
selected={isCustomEmoji(emoji) ? emoji.shortcode === selected : emoji.emoji === selected}
|
||||
{disabled}
|
||||
{skinTone}
|
||||
on:select
|
||||
|
@ -12,7 +12,7 @@
|
||||
showPopup,
|
||||
eventToHTMLElement,
|
||||
ButtonBase,
|
||||
closeTooltip, getEmojiByShortCode
|
||||
closeTooltip, getEmojiByShortCode, getEmojiSkins, getUnicodeEmojiByShortCode
|
||||
} from '../../'
|
||||
import plugin from '../../plugin'
|
||||
import {
|
||||
@ -30,6 +30,7 @@
|
||||
import SkinTonePopup from './SkinTonePopup.svelte'
|
||||
import IconSearch from './icons/Search.svelte'
|
||||
import EmojiGroup from './EmojiGroup.svelte'
|
||||
import { isCustomEmoji } from './types'
|
||||
|
||||
export let embedded = false
|
||||
export let selected: string | undefined
|
||||
@ -98,11 +99,12 @@
|
||||
}
|
||||
|
||||
const sendEmoji = (emoji: EmojiWithGroup): void => {
|
||||
selected = emoji.emoji
|
||||
selected = isCustomEmoji(emoji) ? emoji.shortcode : emoji.emoji
|
||||
addFrequentlyEmojis(emoji)
|
||||
dispatch('close', {
|
||||
emoji: emoji.emoji,
|
||||
codes: emoji.hexcode.split('-').map((hc) => parseInt(hc, 16))
|
||||
// TODO: send ExtendedEmoji
|
||||
emoji: selected
|
||||
// codes: emoji.hexcode.split('-').map((hc) => parseInt(hc, 16))
|
||||
})
|
||||
}
|
||||
|
||||
@ -142,7 +144,8 @@
|
||||
}
|
||||
function handleContextMenu (event: MouseEvent, emoji: EmojiWithGroup, remove: boolean): void {
|
||||
event.preventDefault()
|
||||
if (Array.isArray(emoji.skins) || remove) openContextMenu(event, emoji, remove)
|
||||
const skins = getEmojiSkins(emoji)
|
||||
if (Array.isArray(skins) || remove) openContextMenu(event, emoji, remove)
|
||||
}
|
||||
const clearTimer = (): void => {
|
||||
clearTimeout(timer)
|
||||
@ -155,7 +158,8 @@
|
||||
})
|
||||
}
|
||||
function clampedContextMenu (event: TouchEvent, emoji: EmojiWithGroup, remove: boolean): void {
|
||||
if (timer == null && (Array.isArray(emoji?.skins) || remove)) {
|
||||
const skins = getEmojiSkins(emoji)
|
||||
if (timer == null && (Array.isArray(skins) || remove)) {
|
||||
touchObserver()
|
||||
timer = setTimeout(function () {
|
||||
if (!shownContext) openContextMenu(event, emoji, remove)
|
||||
@ -192,7 +196,7 @@
|
||||
const tempEmojis: string[] = em.emojisString
|
||||
const emojis: EmojiWithGroup[] = []
|
||||
tempEmojis.forEach((te) => {
|
||||
const e = $emojiStore.find((es) => es.hexcode === te)
|
||||
const e = $emojiStore.find((es) => isCustomEmoji(es) ? es.shortcode === te : es.hexcode === te)
|
||||
if (e !== undefined) emojis.push(e)
|
||||
})
|
||||
emojiCategories[index].emojis = emojis
|
||||
@ -265,7 +269,7 @@
|
||||
tooltip={{ label: plugin.string.DefaultSkinTone }}
|
||||
on:click={showSkinMenu}
|
||||
>
|
||||
<span style:font-size={'1.5rem'}>{getEmojiByShortCode(':hand:', skinTone)?.emoji}</span>
|
||||
<span style:font-size={'1.5rem'}>{getUnicodeEmojiByShortCode(':hand:', skinTone)?.emoji}</span>
|
||||
</ButtonBase>
|
||||
</div>
|
||||
<Scroller
|
||||
|
@ -5,17 +5,17 @@
|
||||
//
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import type { Emoji } from 'emojibase'
|
||||
import { Label, closeTooltip, ModernCheckbox } from '../../'
|
||||
import { Label, closeTooltip, ModernCheckbox, getEmojiSkins } from '../../'
|
||||
import { skinTones } from '.'
|
||||
import type { EmojiWithGroup } from '.'
|
||||
|
||||
export let emoji: EmojiWithGroup
|
||||
export let emoji: Emoji
|
||||
export let selected: number
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
closeTooltip()
|
||||
|
||||
const skins: Emoji[] = emoji.skins !== undefined ? [emoji, ...emoji.skins] : []
|
||||
const emojiSkins = getEmojiSkins(emoji)
|
||||
const skins: Emoji[] = emojiSkins !== undefined ? [emoji, ...emojiSkins] : []
|
||||
</script>
|
||||
|
||||
<div class="hulyPopup-container noPadding">
|
||||
|
@ -4,16 +4,17 @@
|
||||
// Licensed under the Eclipse Public License v2.0 (SPDX: EPL-2.0).
|
||||
//
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { type EmojiWithGroup } from '.'
|
||||
import { getEmojiSkins } from '.'
|
||||
import { ButtonBase, closeTooltip } from '../..'
|
||||
import { Emoji } from 'emojibase'
|
||||
|
||||
export let emoji: EmojiWithGroup
|
||||
export let emoji: Emoji
|
||||
export let selected: number
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
const skins: Emoji[] = emoji.skins !== undefined ? [emoji, ...emoji.skins] : []
|
||||
const emojiSkins = getEmojiSkins(emoji)
|
||||
const skins: Emoji[] = emojiSkins !== undefined ? [emoji, ...emojiSkins] : []
|
||||
</script>
|
||||
|
||||
<div class="flex-row-center flex-gap-1">
|
||||
|
@ -16,7 +16,7 @@ import type { IntlString } from '@hcengineering/platform'
|
||||
import type { AnySvelteComponent } from '../..'
|
||||
import type { Emoji } from 'emojibase'
|
||||
|
||||
export type ExtendedEmoji = Emoji // | CustomEmoji
|
||||
export type ExtendedEmoji = Emoji | CustomEmoji
|
||||
export type EmojiWithGroup = ExtendedEmoji & { key: string }
|
||||
|
||||
export interface CustomEmoji {
|
||||
@ -35,6 +35,10 @@ export interface EmojiCategory {
|
||||
emojis?: EmojiWithGroup[]
|
||||
}
|
||||
|
||||
/* export function isCustomEmoji (emoji: EmojiWithGroup): emoji is CustomEmoji & { key: string } {
|
||||
export function isCustomEmoji (emoji: ExtendedEmoji): emoji is CustomEmoji {
|
||||
return 'url' in emoji
|
||||
}*/
|
||||
}
|
||||
|
||||
/* export function isCustomEmoji (emoji: ExtendedEmoji): boolean {
|
||||
return false
|
||||
} */
|
||||
|
@ -19,7 +19,7 @@ import EMOJI_REGEX from 'emojibase-regex'
|
||||
import EMOTICON_REGEX from 'emojibase-regex/emoticon'
|
||||
import SHORTCODE_REGEX from 'emojibase-regex/shortcode'
|
||||
import { getCurrentAccount } from '@hcengineering/core'
|
||||
import { deviceOptionsStore as deviceInfo, type ExtendedEmoji } from '../..'
|
||||
import { deviceOptionsStore as deviceInfo, type ExtendedEmoji, isCustomEmoji } from '../..'
|
||||
import type { EmojiWithGroup } from '.'
|
||||
import { emojiCategories, emojiStore } from '.'
|
||||
|
||||
@ -73,30 +73,41 @@ export async function updateEmojis (lang?: string): Promise<void> {
|
||||
}
|
||||
|
||||
export function getEmojiByHexcode (hexcode: string): EmojiWithGroup | undefined {
|
||||
return get(emojiStore).find((e) => e.hexcode === hexcode)
|
||||
return get(emojiStore).find((e) => !isCustomEmoji(e) && e.hexcode === hexcode)
|
||||
}
|
||||
|
||||
export function getEmojiByEmoticon (emoticon: string | undefined): string | undefined {
|
||||
if (emoticon === undefined) return undefined
|
||||
return findEmoji(e => Array.isArray(e.emoticon) ? e.emoticon.includes(emoticon) : e.emoticon === emoticon)?.emoji
|
||||
const matchEmoji = findEmoji(e => !isCustomEmoji(e) && (Array.isArray(e.emoticon) ? e.emoticon.includes(emoticon) : e.emoticon === emoticon))
|
||||
if (matchEmoji === undefined) return undefined
|
||||
return !isCustomEmoji(matchEmoji) ? matchEmoji.emoji : undefined
|
||||
}
|
||||
|
||||
export function getUnicodeEmojiByShortCode (shortcode: string | undefined, skinTone?: number): Emoji | undefined {
|
||||
const emoji = getEmojiByShortCode(shortcode, skinTone)
|
||||
if (emoji === undefined || isCustomEmoji(emoji)) return undefined
|
||||
}
|
||||
|
||||
export function getEmojiByShortCode (shortcode: string | undefined, skinTone?: number): ExtendedEmoji | undefined {
|
||||
if (shortcode === undefined) return undefined
|
||||
return findEmoji((e) => e.shortcodes?.includes(shortcode.replaceAll(':', '')), skinTone)
|
||||
return findEmoji((e) => {
|
||||
if (isCustomEmoji(e)) return e.shortcode === shortcode
|
||||
return e.shortcodes?.includes(shortcode.replaceAll(':', ''))
|
||||
}, skinTone)
|
||||
}
|
||||
|
||||
function findEmoji (predicate: (e: EmojiWithGroup) => boolean | undefined, skinTone?: number): ExtendedEmoji | undefined {
|
||||
const emojis = get(emojiStore)
|
||||
const matchEmoji = emojis.find(predicate)
|
||||
if (matchEmoji === undefined) return undefined
|
||||
if (isCustomEmoji(matchEmoji)) return matchEmoji
|
||||
if (skinTone === undefined) skinTone = getSkinTone()
|
||||
if (skinTone === 0 || matchEmoji.skins === undefined) return matchEmoji
|
||||
return matchEmoji.skins[skinTone - 1]
|
||||
}
|
||||
|
||||
export const removeFrequentlyEmojis = (emoji: EmojiWithGroup): void => {
|
||||
const hexcode = emoji.hexcode
|
||||
const hexcode = isCustomEmoji(emoji) ? emoji.shortcode : emoji.hexcode
|
||||
if (hexcode === undefined) return
|
||||
|
||||
const frequentlyEmojisKey = getEmojisLocalStorageKey()
|
||||
@ -113,7 +124,7 @@ export const removeFrequentlyEmojis = (emoji: EmojiWithGroup): void => {
|
||||
}
|
||||
export const addFrequentlyEmojis = (emoji: EmojiWithGroup): void => {
|
||||
if (emoji === undefined) return
|
||||
const hexcode = emoji.hexcode
|
||||
const hexcode = isCustomEmoji(emoji) ? emoji.shortcode : emoji.hexcode
|
||||
|
||||
const frequentlyEmojisKey = getEmojisLocalStorageKey()
|
||||
const frequentlyEmojis = window.localStorage.getItem(frequentlyEmojisKey)
|
||||
@ -141,13 +152,23 @@ export const getFrequentlyEmojis = (): EmojiWithGroup[] | undefined => {
|
||||
const parsedEmojis = JSON.parse(frequentlyEmojis)
|
||||
if (!Array.isArray(parsedEmojis)) return undefined
|
||||
const emojis = get(emojiStore)
|
||||
return emojis.filter(e => parsedEmojis.find(pe => pe.hexcode === e.hexcode || e.skins?.find(s => s.hexcode === pe.hexcode) !== undefined) !== undefined)
|
||||
return emojis.filter((e) => {
|
||||
if (isCustomEmoji(e)) {
|
||||
return parsedEmojis.find(pe => pe.hexcode === e.shortcode) !== undefined
|
||||
}
|
||||
return parsedEmojis.find(pe => pe.hexcode === e.hexcode || e.skins?.find(s => s.hexcode === pe.hexcode) !== undefined) !== undefined
|
||||
})
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
export function getEmojiSkins (emoji: ExtendedEmoji): Emoji[] | undefined {
|
||||
if (isCustomEmoji(emoji)) return undefined
|
||||
return emoji.skins
|
||||
}
|
||||
|
||||
export const setSkinTone = (skinTone: number): void => {
|
||||
const skinToneKey = getEmojisLocalStorageKey('skinTone')
|
||||
window.localStorage.setItem(skinToneKey, JSON.stringify(skinTone))
|
||||
|
@ -8,7 +8,7 @@ import {
|
||||
getEventPositionElement,
|
||||
showPopup,
|
||||
type Location,
|
||||
type EmojiWithGroup
|
||||
type EmojiWithGroup, isCustomEmoji
|
||||
} from '@hcengineering/ui'
|
||||
import { type AttributeModel } from '@hcengineering/view'
|
||||
import { get } from 'svelte/store'
|
||||
@ -62,7 +62,8 @@ export async function addReactionAction (
|
||||
closePopup()
|
||||
|
||||
showPopup(EmojiPopup, {}, element, (emoji: EmojiWithGroup) => {
|
||||
if (emoji?.emoji !== undefined) void updateDocReactions(reactions, message, emoji.emoji)
|
||||
// TODO: add custom emoji
|
||||
if (!isCustomEmoji(emoji) && emoji?.emoji !== undefined) void updateDocReactions(reactions, message, emoji.emoji)
|
||||
params?.onClose?.()
|
||||
})
|
||||
params?.onOpen?.()
|
||||
|
@ -8,7 +8,7 @@ import {
|
||||
getEmojiByShortCode,
|
||||
emojiRegex,
|
||||
emojiGlobalRegex,
|
||||
type ExtendedEmoji
|
||||
type ExtendedEmoji, isCustomEmoji
|
||||
} from '@hcengineering/ui'
|
||||
import { type ResolvedPos } from '@tiptap/pm/model'
|
||||
import { type ExtendedRegExpMatchArray, type SingleCommands, type Range, InputRule, PasteRule } from '@tiptap/core'
|
||||
@ -37,7 +37,8 @@ function handleEmoji (
|
||||
}
|
||||
const emoji = getEmojiFunction(match.pop())
|
||||
if (emoji === undefined) return
|
||||
const unicodeEmoji = typeof emoji === 'string' ? emoji : emoji.emoji
|
||||
// TODO: add custom emoji
|
||||
const unicodeEmoji = typeof emoji === 'string' ? emoji : (isCustomEmoji(emoji) ? emoji.shortcode : emoji.emoji)
|
||||
commands.insertContentAt(range, [
|
||||
{
|
||||
type: 'emoji',
|
||||
|
Loading…
Reference in New Issue
Block a user