diff --git a/packages/presentation/src/components/HTMLViewer.svelte b/packages/presentation/src/components/HTMLViewer.svelte index 1cd18df40ea..100ebfcc046 100644 --- a/packages/presentation/src/components/HTMLViewer.svelte +++ b/packages/presentation/src/components/HTMLViewer.svelte @@ -15,13 +15,21 @@
- +
diff --git a/packages/presentation/src/components/LiteMessageViewer.svelte b/packages/presentation/src/components/LiteMessageViewer.svelte index 571c099c6cb..3acfd63304d 100644 --- a/packages/presentation/src/components/LiteMessageViewer.svelte +++ b/packages/presentation/src/components/LiteMessageViewer.svelte @@ -16,13 +16,21 @@ import { MarkupNode, markupToJSON } from '@hcengineering/text' import { Markup } from '@hcengineering/core' import LiteNode from './markup/lite/LiteNode.svelte' + import { loadParseEmojisFunction, ParsedTextWithEmojis } from '@hcengineering/emoji' + import { onMount } from 'svelte' export let message: Markup | MarkupNode export let colorInherit: boolean = false $: node = typeof message === 'string' ? markupToJSON(message) : message + + let parseEmojisFunction: ((text: string) => ParsedTextWithEmojis) | undefined = undefined + + onMount(async () => { + parseEmojisFunction = await loadParseEmojisFunction() + })
- +
diff --git a/packages/presentation/src/components/MessageViewer.svelte b/packages/presentation/src/components/MessageViewer.svelte index 5eb062b4045..761e4c91d4e 100644 --- a/packages/presentation/src/components/MessageViewer.svelte +++ b/packages/presentation/src/components/MessageViewer.svelte @@ -16,6 +16,8 @@
- +
diff --git a/packages/presentation/src/components/markup/Node.svelte b/packages/presentation/src/components/markup/Node.svelte index 9344d1da033..432c0f71777 100644 --- a/packages/presentation/src/components/markup/Node.svelte +++ b/packages/presentation/src/components/markup/Node.svelte @@ -17,10 +17,12 @@ import NodeMarks from './NodeMarks.svelte' import NodeContent from './NodeContent.svelte' + import { ParsedTextWithEmojis } from '@hcengineering/emoji' export let node: MarkupNode - export let single = true + export let singleTextNode = false export let preview = false + export let parseEmojisFunction: ((text: string) => ParsedTextWithEmojis) | undefined = undefined {#if node} @@ -28,9 +30,9 @@ {#if marks.length > 0} - + {:else} - + {/if} {/if} diff --git a/packages/presentation/src/components/markup/NodeContent.svelte b/packages/presentation/src/components/markup/NodeContent.svelte index 7191ff0bbf6..e72b76bd57b 100644 --- a/packages/presentation/src/components/markup/NodeContent.svelte +++ b/packages/presentation/src/components/markup/NodeContent.svelte @@ -21,11 +21,14 @@ import MarkdownNode from './MarkdownNode.svelte' import Node from './Node.svelte' import { getBlobRef } from '../../preview' - import { emojiRegex } from '@hcengineering/emoji' + import { ParsedTextWithEmojis } from '@hcengineering/emoji' export let node: MarkupNode - export let single = true + export let singleTextNode = false export let preview = false + export let parseEmojisFunction: ((text: string) => ParsedTextWithEmojis) | undefined = undefined + + let parsedTextWithEmojis: ParsedTextWithEmojis | undefined = undefined function toRefBlob (blobId: AttrValue): Ref { return blobId as Ref @@ -54,11 +57,8 @@ return value != null ? (typeof value === 'string' ? parseInt(value) : value) : undefined } - const checkEmoji = (nodes: MarkupNode[]): boolean => { - if (nodes.length !== 1) return false - const match = nodes[0].text?.match(emojiRegex) - if (match == null) return false - return match[0] === nodes[0].text + $: if (node.type === MarkupNodeType.text && parseEmojisFunction) { + parsedTextWithEmojis = parseEmojisFunction(node.text ?? '') } @@ -69,13 +69,37 @@ {#if node.type === MarkupNodeType.doc} {#if nodes.length > 0} {#each nodes as node} - + {/each} {/if} {:else if node.type === MarkupNodeType.text} - {node.text} + {#if parsedTextWithEmojis === undefined} + {node.text} + {:else} + {#each parsedTextWithEmojis.nodes as textOrEmoji} + {#if typeof textOrEmoji === 'string'} + {textOrEmoji} + {:else} + + {#if 'image' in textOrEmoji} + {@const blob = toRefBlob(textOrEmoji.image)} + {@const alt = toString(textOrEmoji.emoji)} + {#await getBlobRef(blob) then blobSrc} + + {/await} + {:else} + {textOrEmoji.emoji} + {/if} + + {/if} + {/each} + {/if} {:else if node.type === MarkupNodeType.emoji} - + {#if node.attrs?.kind === 'image'} {@const blob = toRefBlob(attrs.image)} {@const alt = toString(attrs.emoji)} @@ -87,10 +111,10 @@ {/if} {:else if node.type === MarkupNodeType.paragraph} -

+

{#if nodes.length > 0} {#each nodes as node} - + {/each} {/if}

@@ -98,7 +122,7 @@
{#if nodes.length > 0} {#each nodes as node} - + {/each} {/if}
@@ -133,7 +157,7 @@ {:else if nodes.length > 0} {#each nodes as node} - + {/each} {/if} {:else if node.type === MarkupNodeType.hard_break} @@ -143,7 +167,7 @@
    {#if nodes.length > 0} {#each nodes as node} - + {/each} {/if}
@@ -151,7 +175,7 @@
    {#if nodes.length > 0} {#each nodes as node} - + {/each} {/if}
@@ -159,7 +183,7 @@
  • {#if nodes.length > 0} {#each nodes as node} - + {/each} {/if}
  • @@ -171,7 +195,7 @@ {#if nodes.length > 0} {#each nodes as node} - + {/each} {/if} @@ -180,7 +204,7 @@ {#if nodes.length > 0} {#each nodes as node} - + {/each} {/if} @@ -189,7 +213,7 @@ {#if nodes.length > 0} {#each nodes as node} - + {/each} {/if} @@ -199,7 +223,7 @@ {#if nodes.length > 0} {#each nodes as node} - + {/each} {/if} @@ -209,7 +233,7 @@ {#if nodes.length > 0} {#each nodes as node} - + {/each} {/if} @@ -223,7 +247,7 @@ unknown node: "{node.type}" {#if nodes.length > 0} {#each nodes as node} - + {/each} {/if} {/if} diff --git a/packages/presentation/src/components/markup/lite/LiteNode.svelte b/packages/presentation/src/components/markup/lite/LiteNode.svelte index c7c193015e9..6941805fc56 100644 --- a/packages/presentation/src/components/markup/lite/LiteNode.svelte +++ b/packages/presentation/src/components/markup/lite/LiteNode.svelte @@ -17,15 +17,17 @@ import LiteNodeContent from './LiteNodeContent.svelte' import NodeMarks from '../NodeMarks.svelte' + import { ParsedTextWithEmojis } from '@hcengineering/emoji' export let node: MarkupNode export let colorInherit: boolean = false + export let parseEmojisFunction: ((text: string) => ParsedTextWithEmojis) | undefined = undefined {#if node} {@const marks = node.marks ?? []} - + {/if} diff --git a/packages/presentation/src/components/markup/lite/LiteNodeContent.svelte b/packages/presentation/src/components/markup/lite/LiteNodeContent.svelte index 84d018f054f..f89bda14540 100644 --- a/packages/presentation/src/components/markup/lite/LiteNodeContent.svelte +++ b/packages/presentation/src/components/markup/lite/LiteNodeContent.svelte @@ -20,9 +20,13 @@ import ObjectNode from '../ObjectNode.svelte' import NodeMarks from '../NodeMarks.svelte' import { getBlobRef } from '../../../preview' + import { ParsedTextWithEmojis } from '@hcengineering/emoji' export let node: MarkupNode export let colorInherit: boolean = false + export let parseEmojisFunction: ((text: string) => ParsedTextWithEmojis) | undefined = undefined + + let parsedTextWithEmojis: ParsedTextWithEmojis | undefined = undefined function toRefBlob (blobId: AttrValue): Ref { return blobId as Ref @@ -42,6 +46,10 @@ function toString (value: AttrValue | undefined): string | undefined { return value != null ? `${value}` : undefined } + + $: if (node.type === MarkupNodeType.text && parseEmojisFunction) { + parsedTextWithEmojis = parseEmojisFunction(node.text ?? '') + } {#if node} @@ -49,15 +57,35 @@ {@const nodes = node.content ?? []} {#if node.type === MarkupNodeType.doc} - + {:else if node.type === MarkupNodeType.text} - {node.text} + {#if parsedTextWithEmojis === undefined} + {node.text} + {:else} + {#each parsedTextWithEmojis.nodes as textOrEmoji} + {#if typeof textOrEmoji === 'string'} + {textOrEmoji} + {:else} + + {#if 'image' in textOrEmoji} + {@const blob = toRefBlob(textOrEmoji.image)} + {@const alt = toString(textOrEmoji.emoji)} + {#await getBlobRef(blob) then blobSrc} + + {/await} + {:else} + {textOrEmoji.emoji} + {/if} + + {/if} + {/each} + {/if} {:else if node.type === MarkupNodeType.paragraph}

    - +

    {:else if node.type === MarkupNodeType.blockquote} - + {:else if node.type === MarkupNodeType.horizontal_rule} {:else if node.type === MarkupNodeType.code_block} @@ -70,7 +98,7 @@ } ]} > - +

    {:else if node.type === MarkupNodeType.reference} @@ -81,7 +109,7 @@ {#if objectClass !== undefined && objectId !== undefined} {:else} - + {/if} {:else if node.type === MarkupNodeType.emoji} @@ -101,10 +129,10 @@ {:else if node.type === MarkupNodeType.subLink} - + {:else} - + {/if} {/if} diff --git a/packages/presentation/src/components/markup/lite/LiteNodes.svelte b/packages/presentation/src/components/markup/lite/LiteNodes.svelte index ccee927897f..87d2c9e3a43 100644 --- a/packages/presentation/src/components/markup/lite/LiteNodes.svelte +++ b/packages/presentation/src/components/markup/lite/LiteNodes.svelte @@ -16,13 +16,15 @@ import { MarkupNode } from '@hcengineering/text' import LiteNode from './LiteNode.svelte' + import { ParsedTextWithEmojis } from '@hcengineering/emoji' export let nodes: MarkupNode[] export let colorInherit: boolean = false + export let parseEmojisFunction: ((text: string) => ParsedTextWithEmojis) | undefined = undefined {#if nodes} {#each nodes as node} - + {/each} {/if} diff --git a/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-0-400-normal.woff b/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-0-400-normal.woff new file mode 100644 index 00000000000..f6df128c0b9 Binary files /dev/null and b/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-0-400-normal.woff differ diff --git a/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-1-400-normal.woff b/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-1-400-normal.woff new file mode 100644 index 00000000000..9027a7a4bc6 Binary files /dev/null and b/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-1-400-normal.woff differ diff --git a/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-10-400-normal.woff b/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-10-400-normal.woff new file mode 100644 index 00000000000..c52bc59fa6c Binary files /dev/null and b/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-10-400-normal.woff differ diff --git a/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-11-400-normal.woff b/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-11-400-normal.woff new file mode 100644 index 00000000000..cac257a2e64 Binary files /dev/null and b/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-11-400-normal.woff differ diff --git a/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-2-400-normal.woff b/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-2-400-normal.woff new file mode 100644 index 00000000000..9c9ae96d0e8 Binary files /dev/null and b/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-2-400-normal.woff differ diff --git a/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-3-400-normal.woff b/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-3-400-normal.woff new file mode 100644 index 00000000000..dcd5c1364e9 Binary files /dev/null and b/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-3-400-normal.woff differ diff --git a/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-4-400-normal.woff b/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-4-400-normal.woff new file mode 100644 index 00000000000..e051bd6bbd1 Binary files /dev/null and b/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-4-400-normal.woff differ diff --git a/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-5-400-normal.woff b/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-5-400-normal.woff new file mode 100644 index 00000000000..c6817da4265 Binary files /dev/null and b/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-5-400-normal.woff differ diff --git a/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-6-400-normal.woff b/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-6-400-normal.woff new file mode 100644 index 00000000000..e95cce32e80 Binary files /dev/null and b/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-6-400-normal.woff differ diff --git a/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-7-400-normal.woff b/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-7-400-normal.woff new file mode 100644 index 00000000000..485cffade51 Binary files /dev/null and b/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-7-400-normal.woff differ diff --git a/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-8-400-normal.woff b/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-8-400-normal.woff new file mode 100644 index 00000000000..8ca4274e801 Binary files /dev/null and b/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-8-400-normal.woff differ diff --git a/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-9-400-normal.woff b/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-9-400-normal.woff new file mode 100644 index 00000000000..dc2af9d8bb1 Binary files /dev/null and b/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-9-400-normal.woff differ diff --git a/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-emoji-400-normal.woff b/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-emoji-400-normal.woff new file mode 100644 index 00000000000..8be5f8887f8 Binary files /dev/null and b/packages/theme/fonts/complete/woff/noto-color/noto-color-emoji-emoji-400-normal.woff differ diff --git a/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-0-400-normal.woff2 b/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-0-400-normal.woff2 new file mode 100644 index 00000000000..37016bc77dd Binary files /dev/null and b/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-0-400-normal.woff2 differ diff --git a/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-1-400-normal.woff2 b/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-1-400-normal.woff2 new file mode 100644 index 00000000000..b7778aab326 Binary files /dev/null and b/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-1-400-normal.woff2 differ diff --git a/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-10-400-normal.woff2 b/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-10-400-normal.woff2 new file mode 100644 index 00000000000..fd7dac278b2 Binary files /dev/null and b/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-10-400-normal.woff2 differ diff --git a/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-11-400-normal.woff2 b/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-11-400-normal.woff2 new file mode 100644 index 00000000000..07c5df2fbce Binary files /dev/null and b/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-11-400-normal.woff2 differ diff --git a/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-2-400-normal.woff2 b/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-2-400-normal.woff2 new file mode 100644 index 00000000000..d9b1c0da2f2 Binary files /dev/null and b/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-2-400-normal.woff2 differ diff --git a/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-3-400-normal.woff2 b/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-3-400-normal.woff2 new file mode 100644 index 00000000000..464a973ff4e Binary files /dev/null and b/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-3-400-normal.woff2 differ diff --git a/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-4-400-normal.woff2 b/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-4-400-normal.woff2 new file mode 100644 index 00000000000..e6b08ac81d0 Binary files /dev/null and b/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-4-400-normal.woff2 differ diff --git a/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-5-400-normal.woff2 b/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-5-400-normal.woff2 new file mode 100644 index 00000000000..6ebd9524b4f Binary files /dev/null and b/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-5-400-normal.woff2 differ diff --git a/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-6-400-normal.woff2 b/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-6-400-normal.woff2 new file mode 100644 index 00000000000..875d7083931 Binary files /dev/null and b/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-6-400-normal.woff2 differ diff --git a/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-7-400-normal.woff2 b/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-7-400-normal.woff2 new file mode 100644 index 00000000000..001f13c08bf Binary files /dev/null and b/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-7-400-normal.woff2 differ diff --git a/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-8-400-normal.woff2 b/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-8-400-normal.woff2 new file mode 100644 index 00000000000..07a13bc142a Binary files /dev/null and b/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-8-400-normal.woff2 differ diff --git a/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-9-400-normal.woff2 b/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-9-400-normal.woff2 new file mode 100644 index 00000000000..76e3a15afde Binary files /dev/null and b/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-9-400-normal.woff2 differ diff --git a/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-emoji-400-normal.woff2 b/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-emoji-400-normal.woff2 new file mode 100644 index 00000000000..971a348f250 Binary files /dev/null and b/packages/theme/fonts/complete/woff2/noto-color/noto-color-emoji-emoji-400-normal.woff2 differ diff --git a/packages/theme/src/Theme.svelte b/packages/theme/src/Theme.svelte index c333f424da1..1e2837ffda8 100644 --- a/packages/theme/src/Theme.svelte +++ b/packages/theme/src/Theme.svelte @@ -25,15 +25,17 @@ getCurrentTheme, isSystemThemeDark, isThemeDark, - themeStore as themeOptions + themeStore as themeOptions, + getCurrentEmoji } from './' const currentTheme = writable(getCurrentTheme()) const currentFontSize = writable(getCurrentFontSize()) const currentLanguage = writable(getCurrentLanguage()) + const currentEmoji = writable(getCurrentEmoji()) - const setOptions = (currentFont: string, theme: string, language: string) => { - themeOptions.set(new ThemeOptions(currentFont === 'normal-font' ? 16 : 14, isThemeDark(theme), language)) + const setOptions = (currentFont: string, theme: string, language: string, emoji: string) => { + themeOptions.set(new ThemeOptions(currentFont === 'normal-font' ? 16 : 14, isThemeDark(theme), language, emoji)) } const getRealTheme = (theme: string): string => (isThemeDark(theme) ? ThemeVariant.Dark : ThemeVariant.Light) @@ -42,16 +44,22 @@ if (set) { localStorage.setItem('theme', theme) } - document.documentElement.setAttribute('class', `${getRealTheme(theme)} ${getCurrentFontSize()}`) - setOptions(getCurrentFontSize(), theme, getCurrentLanguage()) + document.documentElement.setAttribute( + 'class', + `${getRealTheme(theme)} ${getCurrentFontSize()} ${getCurrentEmoji()}` + ) + setOptions(getCurrentFontSize(), theme, getCurrentLanguage(), getCurrentEmoji()) } const setRootFontSize = (fontsize: string, set = true) => { currentFontSize.set(fontsize) if (set) { localStorage.setItem('fontsize', fontsize) } - document.documentElement.setAttribute('class', `${getRealTheme(getCurrentTheme())} ${fontsize}`) - setOptions(fontsize, getCurrentTheme(), getCurrentLanguage()) + document.documentElement.setAttribute( + 'class', + `${getRealTheme(getCurrentTheme())} ${fontsize} ${getCurrentEmoji()}` + ) + setOptions(fontsize, getCurrentTheme(), getCurrentLanguage(), getCurrentEmoji()) } const setLanguage = async (language: string, set: boolean = true) => { currentLanguage.set(language) @@ -61,7 +69,18 @@ Analytics.setTag('language', language) setMetadata(platform.metadata.locale, $currentLanguage) await loadPluginStrings($currentLanguage, set) - setOptions(getCurrentFontSize(), getCurrentTheme(), language) + setOptions(getCurrentFontSize(), getCurrentTheme(), language, getCurrentEmoji()) + } + const setEmoji = (emoji: string, set = true) => { + currentEmoji.set(emoji) + if (set) { + localStorage.setItem('emoji', emoji) + } + document.documentElement.setAttribute( + 'class', + `${getRealTheme(getCurrentTheme())} ${getCurrentFontSize()} ${emoji}` + ) + setOptions(getCurrentFontSize(), getCurrentTheme(), getCurrentLanguage(), emoji) } setContext('theme', { @@ -76,6 +95,10 @@ currentLanguage, setLanguage }) + setContext('emoji', { + currentEmoji, + setEmoji + }) let remove: any = null diff --git a/packages/theme/src/index.ts b/packages/theme/src/index.ts index 92ca514f894..ef98ab74887 100644 --- a/packages/theme/src/index.ts +++ b/packages/theme/src/index.ts @@ -62,13 +62,18 @@ export const getCurrentLanguage = (): string => { Analytics.setTag('language', lang) return lang } +/** + * @public + */ +export const getCurrentEmoji = (): string => localStorage.getItem('emoji') ?? getDefaultProps('emoji', 'emoji-system') export class ThemeOptions { readonly variant: ThemeVariantType constructor ( readonly fontSize: number, readonly dark: boolean, - readonly language: string + readonly language: string, + readonly emoji: string ) { this.variant = dark ? ThemeVariant.Dark : ThemeVariant.Light } @@ -80,7 +85,8 @@ export function initThemeStore (): void { new ThemeOptions( getCurrentFontSize() === 'normal-font' ? 16 : 14, isThemeDark(getCurrentTheme()), - getCurrentLanguage() + getCurrentLanguage(), + getCurrentEmoji() ) ) } diff --git a/packages/theme/styles/common.scss b/packages/theme/styles/common.scss index b9b1e3ab5e7..5d028df294a 100644 --- a/packages/theme/styles/common.scss +++ b/packages/theme/styles/common.scss @@ -874,6 +874,14 @@ .message.outcoming { border-radius: 0.75rem 0.125rem 0.125rem 0.75rem; } } +.emoji-system {} + +.emoji-noto { + .emoji { + font-family: "Noto Color Emoji"; + } +} + .emoji { &.center { display: flex; @@ -897,4 +905,4 @@ .emoji.fitSize > img { height: 1em; -} \ No newline at end of file +} diff --git a/packages/theme/styles/global.scss b/packages/theme/styles/global.scss index 793cfa3086e..8e2f2b7eabb 100644 --- a/packages/theme/styles/global.scss +++ b/packages/theme/styles/global.scss @@ -33,6 +33,7 @@ @import "./love.scss"; @import "./mono.scss"; +@import "./noto-color.scss"; @font-face { font-family: 'IBM Plex Sans'; diff --git a/packages/theme/styles/noto-color.scss b/packages/theme/styles/noto-color.scss new file mode 100644 index 00000000000..34a472e3e9c --- /dev/null +++ b/packages/theme/styles/noto-color.scss @@ -0,0 +1,120 @@ +/* noto-color-emoji-[0]-400-normal */ +@font-face { + font-family: 'Noto Color Emoji'; + font-style: normal; + font-display: swap; + font-weight: 400; + src: url('../fonts/complete/woff2/noto-color/noto-color-emoji-0-400-normal.woff2') format('woff2'), + url('../fonts/complete/woff/noto-color/noto-color-emoji-0-400-normal.woff') format('woff'); + unicode-range: U+1f1e6-1f1ff; +} + +/* noto-color-emoji-[1]-400-normal */ +@font-face { + font-family: 'Noto Color Emoji'; + font-style: normal; + font-display: swap; + font-weight: 400; + src: url('../fonts/complete/woff2/noto-color/noto-color-emoji-1-400-normal.woff2') format('woff2'), + url('../fonts/complete/woff/noto-color/noto-color-emoji-1-400-normal.woff') format('woff'); + unicode-range: U+200d,U+2620,U+26a7,U+fe0f,U+1f308,U+1f38c,U+1f3c1,U+1f3f3-1f3f4,U+1f6a9,U+e0062-e0063,U+e0065,U+e0067,U+e006c,U+e006e,U+e0073-e0074,U+e0077,U+e007f; +} + +/* noto-color-emoji-[2]-400-normal */ +@font-face { + font-family: 'Noto Color Emoji'; + font-style: normal; + font-display: swap; + font-weight: 400; + src: url('../fonts/complete/woff2/noto-color/noto-color-emoji-2-400-normal.woff2') format('woff2'), + url('../fonts/complete/woff/noto-color/noto-color-emoji-2-400-normal.woff') format('woff'); + unicode-range: U+23,U+2a,U+30-39,U+a9,U+ae,U+200d,U+203c,U+2049,U+20e3,U+2122,U+2139,U+2194-2199,U+21a9-21aa,U+23cf,U+23e9-23ef,U+23f8-23fa,U+24c2,U+25aa-25ab,U+25b6,U+25c0,U+25fb-25fe,U+2611,U+2622-2623,U+2626,U+262a,U+262e-262f,U+2638,U+2640,U+2642,U+2648-2653,U+2660,U+2663,U+2665-2666,U+2668,U+267b,U+267e-267f,U+2695,U+269b-269c,U+26a0,U+26a7,U+26aa-26ab,U+26ce,U+26d4,U+2705,U+2714,U+2716,U+271d,U+2721,U+2733-2734,U+2747,U+274c,U+274e,U+2753-2755,U+2757,U+2764,U+2795-2797,U+27a1,U+27b0,U+27bf,U+2934-2935,U+2b05-2b07,U+2b1b-2b1c,U+2b55,U+3030,U+303d,U+3297,U+3299,U+fe0f,U+1f170-1f171,U+1f17e-1f17f,U+1f18e,U+1f191-1f19a,U+1f201-1f202,U+1f21a,U+1f22f,U+1f232-1f23a,U+1f250-1f251,U+1f310,U+1f3a6,U+1f3b5-1f3b6,U+1f3bc,U+1f3e7,U+1f441,U+1f499-1f49c,U+1f49f-1f4a0,U+1f4a2,U+1f4ac-1f4ad,U+1f4b1-1f4b2,U+1f4b9,U+1f4db,U+1f4f2-1f4f6,U+1f500-1f50a,U+1f515,U+1f518-1f524,U+1f52f-1f53d,U+1f549,U+1f54e,U+1f5a4,U+1f5e8,U+1f5ef,U+1f6ab,U+1f6ad-1f6b1,U+1f6b3,U+1f6b7-1f6bc,U+1f6be,U+1f6c2-1f6c5,U+1f6d0-1f6d1,U+1f6d7,U+1f6dc,U+1f7e0-1f7eb,U+1f7f0,U+1f90d-1f90e,U+1f9e1,U+1fa75-1fa77,U+1faaf; +} + +/* noto-color-emoji-[3]-400-normal */ +@font-face { + font-family: 'Noto Color Emoji'; + font-style: normal; + font-display: swap; + font-weight: 400; + src: url('../fonts/complete/woff2/noto-color/noto-color-emoji-3-400-normal.woff2') format('woff2'), + url('../fonts/complete/woff/noto-color/noto-color-emoji-3-400-normal.woff') format('woff'); + unicode-range: U+231a-231b,U+2328,U+23f0-23f3,U+2602,U+260e,U+2692,U+2694,U+2696-2697,U+2699,U+26b0-26b1,U+26cf,U+26d1,U+26d3,U+2702,U+2709,U+270f,U+2712,U+fe0f,U+1f302,U+1f321,U+1f392-1f393,U+1f3a9,U+1f3bd,U+1f3ee,U+1f3f7,U+1f3fa,U+1f451-1f462,U+1f484,U+1f489-1f48a,U+1f48c-1f48e,U+1f4a1,U+1f4a3,U+1f4b0,U+1f4b3-1f4b8,U+1f4bb-1f4da,U+1f4dc-1f4f1,U+1f4ff,U+1f50b-1f514,U+1f516-1f517,U+1f526-1f529,U+1f52c-1f52e,U+1f550-1f567,U+1f56f-1f570,U+1f576,U+1f587,U+1f58a-1f58d,U+1f5a5,U+1f5a8,U+1f5b1-1f5b2,U+1f5c2-1f5c4,U+1f5d1-1f5d3,U+1f5dc-1f5de,U+1f5e1,U+1f5f3,U+1f6aa,U+1f6ac,U+1f6bd,U+1f6bf,U+1f6c1,U+1f6cb,U+1f6cd-1f6cf,U+1f6d2,U+1f6e0-1f6e1,U+1f6f0,U+1f97b-1f97f,U+1f9af,U+1f9ba,U+1f9e2-1f9e6,U+1f9ea-1f9ec,U+1f9ee-1f9f4,U+1f9f7-1f9ff,U+1fa71-1fa74,U+1fa79-1fa7b,U+1fa86,U+1fa91-1fa93,U+1fa96,U+1fa99-1faa0,U+1faa2-1faa7,U+1faaa-1faae; +} + +/* noto-color-emoji-[4]-400-normal */ +@font-face { + font-family: 'Noto Color Emoji'; + font-style: normal; + font-display: swap; + font-weight: 400; + src: url('../fonts/complete/woff2/noto-color/noto-color-emoji-4-400-normal.woff2') format('woff2'), + url('../fonts/complete/woff/noto-color/noto-color-emoji-4-400-normal.woff') format('woff'); + unicode-range: U+265f,U+26bd-26be,U+26f3,U+26f8,U+fe0f,U+1f004,U+1f0cf,U+1f380-1f384,U+1f386-1f38b,U+1f38d-1f391,U+1f396-1f397,U+1f399-1f39b,U+1f39e-1f39f,U+1f3a3-1f3a5,U+1f3a7-1f3a9,U+1f3ab-1f3b4,U+1f3b7-1f3bb,U+1f3bd-1f3c0,U+1f3c5-1f3c6,U+1f3c8-1f3c9,U+1f3cf-1f3d3,U+1f3f8-1f3f9,U+1f47e,U+1f4e2,U+1f4f7-1f4fd,U+1f52b,U+1f579,U+1f58c-1f58d,U+1f5bc,U+1f6f7,U+1f6f9,U+1f6fc,U+1f93f,U+1f941,U+1f945,U+1f947-1f94f,U+1f9e7-1f9e9,U+1f9f5-1f9f6,U+1fa70-1fa71,U+1fa80-1fa81,U+1fa83-1fa85,U+1fa87-1fa88,U+1fa94-1fa95,U+1fa97-1fa98,U+1faa1,U+1faa9; +} + +/* noto-color-emoji-[5]-400-normal */ +@font-face { + font-family: 'Noto Color Emoji'; + font-style: normal; + font-display: swap; + font-weight: 400; + src: url('../fonts/complete/woff2/noto-color/noto-color-emoji-5-400-normal.woff2') format('woff2'), + url('../fonts/complete/woff/noto-color/noto-color-emoji-5-400-normal.woff') format('woff'); + unicode-range: U+2693,U+26e9-26ea,U+26f1-26f2,U+26f4-26f5,U+26fa,U+26fd,U+2708,U+fe0f,U+1f301,U+1f303,U+1f306-1f307,U+1f309,U+1f310,U+1f3a0-1f3a2,U+1f3aa,U+1f3cd-1f3ce,U+1f3d5,U+1f3d7-1f3db,U+1f3df-1f3e6,U+1f3e8-1f3ed,U+1f3ef-1f3f0,U+1f488,U+1f492,U+1f4ba,U+1f54b-1f54d,U+1f5fa-1f5ff,U+1f680-1f6a2,U+1f6a4-1f6a8,U+1f6b2,U+1f6d1,U+1f6d5-1f6d6,U+1f6dd-1f6df,U+1f6e2-1f6e5,U+1f6e9,U+1f6eb-1f6ec,U+1f6f3-1f6f6,U+1f6f8,U+1f6fa-1f6fb,U+1f9bc-1f9bd,U+1f9ed,U+1f9f3,U+1fa7c; +} + +/* noto-color-emoji-[6]-400-normal */ +@font-face { + font-family: 'Noto Color Emoji'; + font-style: normal; + font-display: swap; + font-weight: 400; + src: url('../fonts/complete/woff2/noto-color/noto-color-emoji-6-400-normal.woff2') format('woff2'), + url('../fonts/complete/woff/noto-color/noto-color-emoji-6-400-normal.woff') format('woff'); + unicode-range: U+2615,U+fe0f,U+1f32d-1f330,U+1f336,U+1f33d,U+1f345-1f37f,U+1f382,U+1f52a,U+1f942-1f944,U+1f950-1f96f,U+1f99e,U+1f9aa,U+1f9c0-1f9cb,U+1fad0-1fadb; +} + +/* noto-color-emoji-[7]-400-normal */ +@font-face { + font-family: 'Noto Color Emoji'; + font-style: normal; + font-display: swap; + font-weight: 400; + src: url('../fonts/complete/woff2/noto-color/noto-color-emoji-7-400-normal.woff2') format('woff2'), + url('../fonts/complete/woff/noto-color/noto-color-emoji-7-400-normal.woff') format('woff'); + unicode-range: U+200d,U+2600-2601,U+2603-2604,U+2614,U+2618,U+26a1,U+26c4-26c5,U+26c8,U+26f0,U+2728,U+2744,U+2b1b,U+2b50,U+fe0f,U+1f300,U+1f304-1f305,U+1f308,U+1f30a-1f30f,U+1f311-1f321,U+1f324-1f32c,U+1f331-1f335,U+1f337-1f33c,U+1f33e-1f344,U+1f3d4,U+1f3d6,U+1f3dc-1f3de,U+1f3f5,U+1f400-1f43f,U+1f490,U+1f4a7,U+1f4ab,U+1f4ae,U+1f525,U+1f54a,U+1f573,U+1f577-1f578,U+1f648-1f64a,U+1f940,U+1f980-1f9ae,U+1f9ba,U+1fa90,U+1faa8,U+1fab0-1fabd,U+1fabf,U+1face-1facf,U+1fae7; +} + +/* noto-color-emoji-[8]-400-normal */ +@font-face { + font-family: 'Noto Color Emoji'; + font-style: normal; + font-display: swap; + font-weight: 400; + src: url('../fonts/complete/woff2/noto-color/noto-color-emoji-8-400-normal.woff2') format('woff2'), + url('../fonts/complete/woff/noto-color/noto-color-emoji-8-400-normal.woff') format('woff'); + unicode-range: U+200d,U+2640,U+2642,U+2695-2696,U+26f7,U+26f9,U+2708,U+2764,U+fe0f,U+1f33e,U+1f373,U+1f37c,U+1f384-1f385,U+1f393,U+1f3a4,U+1f3a8,U+1f3c2-1f3c4,U+1f3c7,U+1f3ca-1f3cc,U+1f3eb,U+1f3ed,U+1f3fb-1f3ff,U+1f466-1f478,U+1f47c,U+1f481-1f483,U+1f486-1f487,U+1f48b,U+1f48f,U+1f491,U+1f4bb-1f4bc,U+1f527,U+1f52c,U+1f574-1f575,U+1f57a,U+1f645-1f647,U+1f64b,U+1f64d-1f64e,U+1f680,U+1f692,U+1f6a3,U+1f6b4-1f6b6,U+1f6c0,U+1f6cc,U+1f91d,U+1f926,U+1f930-1f931,U+1f934-1f93a,U+1f93c-1f93e,U+1f977,U+1f9af-1f9b3,U+1f9b8-1f9b9,U+1f9bc-1f9bd,U+1f9cc-1f9cf,U+1f9d1-1f9df,U+1fa82,U+1fac3-1fac5; +} + +/* noto-color-emoji-[9]-400-normal */ +@font-face { + font-family: 'Noto Color Emoji'; + font-style: normal; + font-display: swap; + font-weight: 400; + src: url('../fonts/complete/woff2/noto-color/noto-color-emoji-9-400-normal.woff2') format('woff2'), + url('../fonts/complete/woff/noto-color/noto-color-emoji-9-400-normal.woff') format('woff'); + unicode-range: U+200d,U+261d,U+2620,U+2639-263a,U+2665,U+270a-270d,U+2728,U+2763-2764,U+2b50,U+fe0f,U+1f31a-1f31f,U+1f32b,U+1f383,U+1f389,U+1f3fb-1f3ff,U+1f440-1f450,U+1f463-1f465,U+1f479-1f47b,U+1f47d-1f480,U+1f485,U+1f48b-1f48c,U+1f493-1f49f,U+1f4a4-1f4a6,U+1f4a8-1f4ab,U+1f4af,U+1f525,U+1f573,U+1f590,U+1f595-1f596,U+1f5a4,U+1f5e3,U+1f600-1f644,U+1f648-1f64a,U+1f64c,U+1f64f,U+1f90c-1f925,U+1f927-1f92f,U+1f932-1f933,U+1f970-1f976,U+1f978-1f97a,U+1f9a0,U+1f9b4-1f9b7,U+1f9bb,U+1f9be-1f9bf,U+1f9d0,U+1f9e0-1f9e1,U+1fa75-1fa79,U+1fac0-1fac2,U+1fae0-1fae6,U+1fae8,U+1faf0-1faf8; +} + +/* noto-color-emoji-emoji-400-normal */ +@font-face { + font-family: 'Noto Color Emoji'; + font-style: normal; + font-display: swap; + font-weight: 400; + src: url('../fonts/complete/woff2/noto-color/noto-color-emoji-emoji-400-normal.woff2') format('woff2'), + url('../fonts/complete/woff/noto-color/noto-color-emoji-emoji-400-normal.woff') format('woff'); + unicode-range: U+200D,U+203C,U+2049,U+20E3,U+2139,U+2194-2199,U+21A9-21AA,U+231A-231B,U+2328,U+23CF,U+23E9-23F3,U+23F8-23FA,U+24C2,U+25AA-25AB,U+25B6,U+25C0,U+25FB-25FE,U+2600-2604,U+260E,U+2611,U+2614-2615,U+2618,U+261D,U+2620,U+2622-2623,U+2626,U+262A,U+262E-262F,U+2638-263A,U+2640,U+2642,U+2648-2653,U+265F-2660,U+2663,U+2665-2666,U+2668,U+267B,U+267E-267F,U+2692-2697,U+2699,U+269B-269C,U+26A0-26A1,U+26A7,U+26AA-26AB,U+26B0-26B1,U+26BD-26BE,U+26C4-26C5,U+26C8,U+26CE-26CF,U+26D1,U+26D3-26D4,U+26E9-26EA,U+26F0-26F5,U+26F7-26FA,U+26FD,U+2702,U+2705,U+2708-270D,U+270F,U+2712,U+2714,U+2716,U+271D,U+2721,U+2728,U+2733-2734,U+2744,U+2747,U+274C,U+274E,U+2753-2755,U+2757,U+2763-2764,U+2795-2797,U+27A1,U+27B0,U+27BF,U+2934-2935,U+2B05-2B07,U+2B1B-2B1C,U+2B50,U+2B55,U+3030,U+303D,U+3297,U+3299,U+FE0F,U+1F004,U+1F0CF,U+1F170-1F171,U+1F17E-1F17F,U+1F18E,U+1F191-1F19A,U+1F1E6-1F1FF,U+1F201-1F202,U+1F21A,U+1F22F,U+1F232-1F23A,U+1F250-1F251,U+1F300-1F321,U+1F324-1F393,U+1F396-1F397,U+1F399-1F39B,U+1F39E-1F3F0,U+1F3F3-1F3F5,U+1F3F7-1F4FD,U+1F4FF-1F53D,U+1F549-1F54E,U+1F550-1F567,U+1F56F-1F570,U+1F573-1F57A,U+1F587,U+1F58A-1F58D,U+1F590,U+1F595-1F596,U+1F5A4-1F5A5,U+1F5A8,U+1F5B1-1F5B2,U+1F5BC,U+1F5C2-1F5C4,U+1F5D1-1F5D3,U+1F5DC-1F5DE,U+1F5E1,U+1F5E3,U+1F5E8,U+1F5EF,U+1F5F3,U+1F5FA-1F64F,U+1F680-1F6C5,U+1F6CB-1F6D2,U+1F6D5-1F6D7,U+1F6DC-1F6E5,U+1F6E9,U+1F6EB-1F6EC,U+1F6F0,U+1F6F3-1F6FC,U+1F7E0-1F7EB,U+1F7F0,U+1F90C-1F93A,U+1F93C-1F945,U+1F947-1F9FF,U+1FA70-1FA7C,U+1FA80-1FA88,U+1FA90-1FABD,U+1FABF-1FAC5,U+1FACE-1FADB,U+1FAE0-1FAE8,U+1FAF0-1FAF8,U+E0062-E0063,U+E0065,U+E0067,U+E006C,U+E006E,U+E0073-E0074,U+E0077,U+E007F,U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; +} \ No newline at end of file diff --git a/packages/ui/lang/cs.json b/packages/ui/lang/cs.json index c79e6d4da83..704862577a5 100644 --- a/packages/ui/lang/cs.json +++ b/packages/ui/lang/cs.json @@ -103,6 +103,9 @@ "Yesterday": "Včera", "ThisWeek": "Tento týden", "ThisMonth": "Tento měsíc", - "ThisYear": "Tento rok" + "ThisYear": "Tento rok", + "EmojiStyle": "Styl emoji", + "EmojiSystem": "Výchozí systémové", + "EmojiNoto": "Noto Color" } } diff --git a/packages/ui/lang/de.json b/packages/ui/lang/de.json index a13bfe536fb..55d8a0d147b 100644 --- a/packages/ui/lang/de.json +++ b/packages/ui/lang/de.json @@ -104,6 +104,9 @@ "Yesterday": "Gestern", "ThisWeek": "Diese Woche", "ThisMonth": "Diesen Monat", - "ThisYear": "Dieses Jahr" + "ThisYear": "Dieses Jahr", + "EmojiStyle": "Emoji-Stil", + "EmojiSystem": "Systemstandard", + "EmojiNoto": "Noto Color" } } diff --git a/packages/ui/lang/en.json b/packages/ui/lang/en.json index f14b341ecaf..a7f6282a175 100644 --- a/packages/ui/lang/en.json +++ b/packages/ui/lang/en.json @@ -104,6 +104,9 @@ "Yesterday": "Yesterday", "ThisWeek": "This week", "ThisMonth": "This month", - "ThisYear": "This year" + "ThisYear": "This year", + "EmojiStyle": "Emoji Style", + "EmojiSystem": "System Default", + "EmojiNoto": "Noto Color" } } diff --git a/packages/ui/lang/es.json b/packages/ui/lang/es.json index ffab90004ed..1f8fece65e5 100644 --- a/packages/ui/lang/es.json +++ b/packages/ui/lang/es.json @@ -104,6 +104,9 @@ "Yesterday": "Ayer", "ThisWeek": "Esta semana", "ThisMonth": "Este mes", - "ThisYear": "Este año" + "ThisYear": "Este año", + "EmojiStyle": "Estilo de emoji", + "EmojiSystem": "Predeterminado del sistema", + "EmojiNoto": "Noto Color" } } diff --git a/packages/ui/lang/fr.json b/packages/ui/lang/fr.json index 5b6a329e123..5081fc70bee 100644 --- a/packages/ui/lang/fr.json +++ b/packages/ui/lang/fr.json @@ -104,6 +104,9 @@ "Yesterday": "Hier", "ThisWeek": "Cette semaine", "ThisMonth": "Ce mois-ci", - "ThisYear": "Cette année" + "ThisYear": "Cette année", + "EmojiStyle": "Style d'émoji", + "EmojiSystem": "Par défaut du système", + "EmojiNoto": "Noto Color" } } diff --git a/packages/ui/lang/it.json b/packages/ui/lang/it.json index 7ea036dc094..15c212ddba4 100644 --- a/packages/ui/lang/it.json +++ b/packages/ui/lang/it.json @@ -104,6 +104,9 @@ "Yesterday": "Ieri", "ThisWeek": "Questa settimana", "ThisMonth": "Questo mese", - "ThisYear": "Quest'anno" + "ThisYear": "Quest'anno", + "EmojiStyle": "Stile emoji", + "EmojiSystem": "Predefinito di sistema", + "EmojiNoto": "Noto Color" } } diff --git a/packages/ui/lang/ja.json b/packages/ui/lang/ja.json index ad16111fd41..c6d9531c155 100644 --- a/packages/ui/lang/ja.json +++ b/packages/ui/lang/ja.json @@ -104,6 +104,9 @@ "Yesterday": "昨日", "ThisWeek": "今週", "ThisMonth": "今月", - "ThisYear": "今年" + "ThisYear": "今年", + "EmojiStyle": "絵文字スタイル", + "EmojiSystem": "システムデフォルト", + "EmojiNoto": "Noto Color" } } diff --git a/packages/ui/lang/pt.json b/packages/ui/lang/pt.json index 53a85bcda86..8e08ad8965c 100644 --- a/packages/ui/lang/pt.json +++ b/packages/ui/lang/pt.json @@ -104,6 +104,9 @@ "Yesterday": "Ontem", "ThisWeek": "Esta semana", "ThisMonth": "Este mês", - "ThisYear": "Este ano" + "ThisYear": "Este ano", + "EmojiStyle": "Estilo de emoji", + "EmojiSystem": "Padrão do sistema", + "EmojiNoto": "Noto Color" } } diff --git a/packages/ui/lang/ru.json b/packages/ui/lang/ru.json index 5b26730e3bf..081716b7b24 100644 --- a/packages/ui/lang/ru.json +++ b/packages/ui/lang/ru.json @@ -104,6 +104,9 @@ "Yesterday": "Вчера", "ThisWeek": "Эта неделя", "ThisMonth": "Этот месяц", - "ThisYear": "Этот год" + "ThisYear": "Этот год", + "EmojiStyle": "Стиль эмодзи", + "EmojiSystem": "Системный по умолчанию", + "EmojiNoto": "Noto Color" } } diff --git a/packages/ui/lang/zh.json b/packages/ui/lang/zh.json index 194607157dc..0cab25fd23c 100644 --- a/packages/ui/lang/zh.json +++ b/packages/ui/lang/zh.json @@ -104,6 +104,9 @@ "Yesterday": "昨天", "ThisWeek": "本周", "ThisMonth": "本月", - "ThisYear": "今年" + "ThisYear": "今年", + "EmojiStyle": "表情样式", + "EmojiSystem": "系统默认", + "EmojiNoto": "Noto Color" } } diff --git a/packages/ui/src/components/internal/SettingsPopup.svelte b/packages/ui/src/components/internal/SettingsPopup.svelte index 30344b0b9c5..d89e47a5eb4 100644 --- a/packages/ui/src/components/internal/SettingsPopup.svelte +++ b/packages/ui/src/components/internal/SettingsPopup.svelte @@ -31,6 +31,7 @@ modalStore, eventToHTMLElement } from '../..' + import EmojiStyle from './icons/EmojiStyle.svelte' const { currentFontSize, setFontSize } = getContext<{ currentFontSize: Readable @@ -46,6 +47,11 @@ setLanguage: (language: string) => void }>('lang') + const { currentEmoji, setEmoji } = getContext<{ + currentEmoji: Readable + setEmoji: (emoji: string) => void + }>('emoji') + const fontsizes: Array<{ id: string, label: IntlString, size: number }> = [ { id: 'normal-font', label: ui.string.Spacious, size: 16 }, { id: 'small-font', label: ui.string.Compact, size: 14 } @@ -57,6 +63,11 @@ { id: 'theme-system', label: ui.string.ThemeSystem } ] + const emojis: Array<{ id: string, label: IntlString }> = [ + { id: 'emoji-system', label: ui.string.EmojiSystem }, + { id: 'emoji-noto', label: ui.string.EmojiNoto } + ] + const uiLangs = new Set(getMetadata(ui.metadata.Languages)) const langs = [ { id: 'en', label: ui.string.English, logo: '🇺🇸' }, @@ -99,9 +110,15 @@ setLanguage(language) } + function selectEmoji (emoji: string): void { + if ($currentEmoji === emoji) return + setEmoji(emoji) + } + $: $deviceInfo.theme = $currentTheme $: fontsize = fontsizes.find((fs) => fs.id === $currentFontSize) ?? fontsizes[0] $: language = langs.find((lang) => lang.id === $currentLanguage) ?? langs[0] + $: emoji = emojis.find((e) => e.id === $currentEmoji) ?? emojis[0]
    @@ -163,6 +180,34 @@
    + + +
    + {/if} diff --git a/plugins/emoji-resources/src/components/EmojiPopup.svelte b/plugins/emoji-resources/src/components/EmojiPopup.svelte index 9055bc14061..4f9799080e0 100644 --- a/plugins/emoji-resources/src/components/EmojiPopup.svelte +++ b/plugins/emoji-resources/src/components/EmojiPopup.svelte @@ -283,7 +283,7 @@ tooltip={{ label: emojiPlugin.string.DefaultSkinTone }} on:click={showSkinMenu} > - {getUnicodeEmojiByShortCode(':hand:', skinTone)?.emoji} + {getUnicodeEmojiByShortCode(':hand:', skinTone)?.emoji}
    - {skin.emoji} + {skin.emoji} {#if label}{/if} {#if disabled}{/if} diff --git a/plugins/emoji-resources/src/components/SkinToneTooltip.svelte b/plugins/emoji-resources/src/components/SkinToneTooltip.svelte index b00f9ac6e29..13b080e8a55 100644 --- a/plugins/emoji-resources/src/components/SkinToneTooltip.svelte +++ b/plugins/emoji-resources/src/components/SkinToneTooltip.svelte @@ -35,7 +35,7 @@ closeTooltip() }} > - {skin.emoji} + {skin.emoji} {/each}
    diff --git a/plugins/emoji-resources/src/index.ts b/plugins/emoji-resources/src/index.ts index 9e6f04bd47e..c9d3edd9bb7 100644 --- a/plugins/emoji-resources/src/index.ts +++ b/plugins/emoji-resources/src/index.ts @@ -2,7 +2,7 @@ import type { Resources } from '@hcengineering/platform' import EmojiPopup from './components/EmojiPopup.svelte' import SettingsEmojiTable from './components/settings/SettingsEmojiTable.svelte' import WorkbenchExtension from './components/WorkbenchExtension.svelte' -import { getCustomEmoji, getEmojiByEmoticon, getEmojiByShortCode } from './utils' +import { getCustomEmoji, getEmojiByEmoticon, getEmojiByShortCode, parseTextWithEmojis } from './utils' export { default as EmojiPresenter } from './components/EmojiPresenter.svelte' @@ -17,6 +17,7 @@ export default async (): Promise => ({ functions: { GetEmojiByEmoticon: getEmojiByEmoticon, GetEmojiByShortCode: getEmojiByShortCode, - GetCustomEmoji: getCustomEmoji + GetCustomEmoji: getCustomEmoji, + ParseTextWithEmojis: parseTextWithEmojis } }) diff --git a/plugins/emoji-resources/src/utils.ts b/plugins/emoji-resources/src/utils.ts index 596eceb0438..0cb6984ddef 100644 --- a/plugins/emoji-resources/src/utils.ts +++ b/plugins/emoji-resources/src/utils.ts @@ -1,5 +1,13 @@ -import { isCustomEmoji, fetchEmojis, fetchMessages } from '@hcengineering/emoji' -import type { EmojiWithGroup, ExtendedEmoji, Locale, Emoji, CustomEmoji } from '@hcengineering/emoji' +import { emojiGlobalRegex, shortcodeGlobalRegex, isCustomEmoji, fetchEmojis, fetchMessages } from '@hcengineering/emoji' +import type { + EmojiWithGroup, + ExtendedEmoji, + Locale, + Emoji, + CustomEmoji, + TextOrEmoji, + ParsedTextWithEmojis +} from '@hcengineering/emoji' import { emojiCategories } from './types' import { unicodeEmojiStore, customEmojiStore, getSkinTone } from './store' import { get } from 'svelte/store' @@ -109,3 +117,43 @@ export function getEmojiSkins (emoji: ExtendedEmoji): Emoji.Emoji[] | undefined if (isCustomEmoji(emoji)) return undefined return emoji.skins } + +export function parseTextWithEmojis (text: string): ParsedTextWithEmojis { + const matches = [...text.matchAll(emojiGlobalRegex), ...text.matchAll(shortcodeGlobalRegex)] + if (matches.length === 0) return { nodes: [text], emojisOnly: false } + matches.sort((a, b) => a.index - b.index) + + const nodes: TextOrEmoji[] = [] + let emojisOnly: boolean = true + + const pushNode = (node: TextOrEmoji): void => { + if (typeof node === 'string') { + if (node !== '') { + emojisOnly = false + nodes.push(node) + } + } else { + nodes.push(node) + } + } + + let startIndex = 0 + for (let index = 0; index < matches.length; index++) { + const matchStart = matches[index].index + pushNode(text.substring(startIndex, matchStart)) + startIndex = matchStart + matches[index][0].length + const emojiText = text.substring(matches[index].index, startIndex) + if (emojiText.startsWith(':')) { + const customEmoji = getCustomEmoji(emojiText) + if (customEmoji === undefined) { + pushNode(emojiText) + } else { + pushNode({ emoji: emojiText, image: customEmoji.image }) + } + } else { + pushNode({ emoji: emojiText }) + } + } + pushNode(text.substring(startIndex, text.length)) + return { nodes, emojisOnly } +} diff --git a/plugins/emoji/src/plugin.ts b/plugins/emoji/src/plugin.ts index 27989daf26f..bc38994a4fc 100644 --- a/plugins/emoji/src/plugin.ts +++ b/plugins/emoji/src/plugin.ts @@ -15,7 +15,7 @@ import { Asset, type IntlString, plugin, type Plugin, Resource } from '@hcengineering/platform' import { AnyComponent } from '@hcengineering/ui' import type { Class, Ref, Doc } from '@hcengineering/core' -import { CustomEmoji, ExtendedEmoji } from './types' +import { CustomEmoji, ExtendedEmoji, ParsedTextWithEmojis } from './types' /** @public */ export const emojiId = 'emoji' as Plugin @@ -90,7 +90,8 @@ export const emojiPlugin = plugin(emojiId, { GetEmojiByShortCode: '' as Resource< (shortcode: string | undefined, skinTone?: number) => ExtendedEmoji | undefined >, - GetCustomEmoji: '' as Resource<(shortcode: string | undefined, skinTone?: number) => CustomEmoji | undefined> + GetCustomEmoji: '' as Resource<(shortcode: string | undefined, skinTone?: number) => CustomEmoji | undefined>, + ParseTextWithEmojis: '' as Resource<(text: string) => ParsedTextWithEmojis> } }) diff --git a/plugins/emoji/src/types.ts b/plugins/emoji/src/types.ts index 22f814becc3..bde8a69068c 100644 --- a/plugins/emoji/src/types.ts +++ b/plugins/emoji/src/types.ts @@ -18,6 +18,13 @@ import type { Blob, Doc, Ref } from '@hcengineering/core' export { default as Emoji } from 'emojibase' export type ExtendedEmoji = Emoji | CustomEmoji export type EmojiWithGroup = ExtendedEmoji & { key: string } +export type TextOrEmoji = string | { emoji: string } | { emoji: string, image: Ref } + +/** @public */ +export interface ParsedTextWithEmojis { + nodes: TextOrEmoji[] + emojisOnly: boolean +} /** @public */ export interface CustomEmoji extends Doc { diff --git a/plugins/emoji/src/utils.ts b/plugins/emoji/src/utils.ts index 2c313a80d2a..6e52bdcba88 100644 --- a/plugins/emoji/src/utils.ts +++ b/plugins/emoji/src/utils.ts @@ -27,6 +27,9 @@ import { type MessagesDataset, type ShortcodesDataset } from 'emojibase' +import emojiPlugin from './plugin' +import { getResource } from '@hcengineering/platform' +import { ParsedTextWithEmojis } from './types' export const emojiRegex = new RegExp(`(?:^|\\s)(${EMOJI_REGEX.source})$`) export const emojiGlobalRegex = new RegExp(EMOJI_REGEX.source, EMOJI_REGEX.flags + 'g') @@ -69,4 +72,13 @@ async function fetchMessages (locale: Locale, options?: FetchFromCDNOptions): Pr } } -export { fetchEmojis, fetchMessages, type Locale } +async function loadParseEmojisFunction (): Promise<((text: string) => ParsedTextWithEmojis) | undefined> { + try { + return await getResource(emojiPlugin.functions.ParseTextWithEmojis) + } catch (e) { + console.log('Cannot locate emoji parsing function') + return undefined + } +} + +export { fetchEmojis, fetchMessages, loadParseEmojisFunction, type Locale }