mirror of
https://github.com/hcengineering/platform.git
synced 2025-05-10 17:30:51 +00:00
202 lines
8.0 KiB
TypeScript
202 lines
8.0 KiB
TypeScript
//
|
|
// Copyright © 2025 Hardcore Engineering Inc.
|
|
//
|
|
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License. You may
|
|
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
//
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
import { get } from 'svelte/store'
|
|
import type { Emoji, Locale } from 'emojibase'
|
|
import { fetchEmojis, fetchMessages } from 'emojibase'
|
|
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, isCustomEmoji } from '../..'
|
|
import type { EmojiWithGroup } from '.'
|
|
import { emojiCategories, emojiStore } from '.'
|
|
|
|
export const emojiRegex = EMOJI_REGEX
|
|
export const emojiGlobalRegex = new RegExp(EMOJI_REGEX.source, EMOJI_REGEX.flags + 'g')
|
|
|
|
export const emoticonRegex = new RegExp(`(?:^|\\s)(${EMOTICON_REGEX.source})$`)
|
|
export const emoticonGlobalRegex = new RegExp(`(?<!\\S)${EMOTICON_REGEX.source}(?!\\S)`, EMOTICON_REGEX.flags + 'g')
|
|
|
|
export const shortcodeRegex = new RegExp(`(?:^|\\s)(${SHORTCODE_REGEX.source})$`)
|
|
export const shortcodeGlobalRegex = new RegExp(`(?<!\\S)${SHORTCODE_REGEX.source}(?!\\S)`, SHORTCODE_REGEX.flags + 'g')
|
|
|
|
export async function loadEmojis (lang?: string): Promise<EmojiWithGroup[]> {
|
|
const local = lang ?? get(deviceInfo).language ?? 'en'
|
|
const englishEmojis =
|
|
local === 'en'
|
|
? await fetchEmojis('en', { version: '15.0', shortcodes: ['iamcal'] })
|
|
: await fetchEmojis('en', { compact: true, version: '15.0', shortcodes: ['iamcal'] })
|
|
const languageEmojis = local === 'en' ? null : await fetchEmojis(local as Locale, { version: '15.0' })
|
|
const messages = await fetchMessages(local as Locale)
|
|
const groups = messages.groups
|
|
const groupKeys = new Map<number, string>(groups.map((group, index) => [index, group.key]))
|
|
|
|
const categories = new Map<string, string>()
|
|
emojiCategories.forEach((cat) => {
|
|
if (Array.isArray(cat.categories)) cat.categories.forEach((c) => categories.set(c, cat.id))
|
|
else if (typeof cat.categories === 'string') categories.set(cat.categories, cat.id)
|
|
})
|
|
|
|
const emojis =
|
|
languageEmojis !== null
|
|
? languageEmojis.map((langEmoji, index) => {
|
|
return {
|
|
...langEmoji,
|
|
tags: [...(englishEmojis[index]?.tags ?? []), ...(langEmoji?.tags ?? [])],
|
|
shortcodes: [...(englishEmojis[index]?.shortcodes ?? []), ...(langEmoji?.shortcodes ?? [])]
|
|
}
|
|
})
|
|
: (englishEmojis as Emoji[])
|
|
|
|
return emojis
|
|
.filter((e) => e.group !== 2 && e.group !== undefined)
|
|
.map((e) => {
|
|
return { ...e, key: categories.get(groupKeys.get(e?.group ?? 0) ?? '') ?? '' }
|
|
})
|
|
}
|
|
|
|
export async function updateEmojis (lang?: string): Promise<void> {
|
|
const emojis = await loadEmojis(lang)
|
|
emojis.push({
|
|
shortcode: 'huly',
|
|
label: 'huly',
|
|
url: 'https://fonts.gstatic.com/s/e/notoemoji/latest/1f979/512.gif',
|
|
tags: ['huly'],
|
|
key: 'flags'
|
|
})
|
|
emojiStore.set(emojis)
|
|
}
|
|
|
|
export function getEmojiByHexcode (hexcode: string): EmojiWithGroup | undefined {
|
|
return get(emojiStore).find((e) => !isCustomEmoji(e) && e.hexcode === hexcode)
|
|
}
|
|
|
|
export function getEmojiByEmoticon (emoticon: string | undefined): string | undefined {
|
|
if (emoticon === undefined) return undefined
|
|
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
|
|
return emoji
|
|
}
|
|
|
|
export function getEmojiByShortCode (shortcode: string | undefined, skinTone?: number): ExtendedEmoji | undefined {
|
|
if (shortcode === undefined) return undefined
|
|
const pureShortcode = shortcode.replaceAll(':', '')
|
|
return findEmoji((e) => {
|
|
if (isCustomEmoji(e)) return e.shortcode === pureShortcode
|
|
return e.shortcodes?.includes(pureShortcode)
|
|
}, 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 = isCustomEmoji(emoji) ? emoji.shortcode : emoji.hexcode
|
|
if (hexcode === undefined) return
|
|
|
|
const frequentlyEmojisKey = getEmojisLocalStorageKey()
|
|
const frequentlyEmojis = window.localStorage.getItem(frequentlyEmojisKey)
|
|
if (frequentlyEmojis != null) {
|
|
const parsedEmojis = JSON.parse(frequentlyEmojis)
|
|
if (Array.isArray(parsedEmojis)) {
|
|
window.localStorage.setItem(
|
|
frequentlyEmojisKey,
|
|
JSON.stringify(parsedEmojis.filter((pe) => pe.hexcode !== hexcode))
|
|
)
|
|
}
|
|
}
|
|
}
|
|
export const addFrequentlyEmojis = (emoji: EmojiWithGroup): void => {
|
|
if (emoji === undefined) return
|
|
const hexcode = isCustomEmoji(emoji) ? emoji.shortcode : emoji.hexcode
|
|
|
|
const frequentlyEmojisKey = getEmojisLocalStorageKey()
|
|
const frequentlyEmojis = window.localStorage.getItem(frequentlyEmojisKey)
|
|
const empty = frequentlyEmojis == null
|
|
|
|
if (!empty) {
|
|
const parsedEmojis = JSON.parse(frequentlyEmojis)
|
|
if (Array.isArray(parsedEmojis)) {
|
|
const index = parsedEmojis.findIndex((pe) => pe.hexcode === hexcode)
|
|
if (index === -1) parsedEmojis.push({ hexcode, count: 1 })
|
|
else parsedEmojis[index].count++
|
|
parsedEmojis.sort((a, b) => b.count - a.count)
|
|
window.localStorage.setItem(frequentlyEmojisKey, JSON.stringify(parsedEmojis))
|
|
return undefined
|
|
}
|
|
}
|
|
window.localStorage.setItem(frequentlyEmojisKey, JSON.stringify([{ hexcode, count: 1 }]))
|
|
}
|
|
export const getFrequentlyEmojis = (): EmojiWithGroup[] | undefined => {
|
|
const frequentlyEmojisKey = getEmojisLocalStorageKey()
|
|
const frequentlyEmojis = window.localStorage.getItem(frequentlyEmojisKey)
|
|
if (frequentlyEmojis == null) return undefined
|
|
|
|
try {
|
|
const parsedEmojis = JSON.parse(frequentlyEmojis)
|
|
if (!Array.isArray(parsedEmojis)) return undefined
|
|
const emojis = get(emojiStore)
|
|
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))
|
|
}
|
|
export const getSkinTone = (): number => {
|
|
const skinToneKey = getEmojisLocalStorageKey('skinTone')
|
|
const skinTone = window.localStorage.getItem(skinToneKey)
|
|
if (skinTone == null) return 0
|
|
|
|
try {
|
|
return JSON.parse(skinTone)
|
|
} catch (e) {
|
|
console.error(e)
|
|
return 0
|
|
}
|
|
}
|
|
|
|
function getEmojisLocalStorageKey (suffix: string = 'frequently'): string {
|
|
const me = getCurrentAccount()
|
|
return `emojis.${suffix}.${me.uuid}`
|
|
}
|