mirror of
https://github.com/hcengineering/platform.git
synced 2025-05-18 05:28:05 +00:00
211 lines
6.1 KiB
Svelte
211 lines
6.1 KiB
Svelte
<script lang="ts">
|
|
import emojiRegex from 'emoji-regex'
|
|
import { getContext } from 'svelte'
|
|
import { createEventDispatcher } from 'svelte'
|
|
import { IntlString } from '@hcengineering/platform'
|
|
import { Label, tooltip, Scroller, emojiSP } from '@hcengineering/ui'
|
|
import type { AnySvelteComponent } from '@hcengineering/ui'
|
|
import Emoji from './icons/Emoji.svelte'
|
|
import Food from './icons/Food.svelte'
|
|
import Nature from './icons/Nature.svelte'
|
|
import Objects from './icons/Objects.svelte'
|
|
import Places from './icons/Places.svelte'
|
|
import Symbols from './icons/Symbols.svelte'
|
|
import Work from './icons/Work.svelte'
|
|
import plugin from '../plugin'
|
|
|
|
let div: HTMLDivElement
|
|
const regex = emojiRegex()
|
|
|
|
const { currentFontSize } = getContext('fontsize') as { currentFontSize: string }
|
|
|
|
function getEmojis (startCode: number, endCode: number, postfix?: number[]): (string | undefined)[] {
|
|
return [...Array(endCode - startCode + 1).keys()].map((v) => {
|
|
const str = postfix ? String.fromCodePoint(v + startCode, ...postfix) : String.fromCodePoint(v + startCode)
|
|
if ([...str.matchAll(regex)].length > 0) return str
|
|
return undefined
|
|
})
|
|
}
|
|
|
|
interface Category {
|
|
id: string
|
|
label: IntlString
|
|
emojis: (string | undefined)[]
|
|
icon: AnySvelteComponent
|
|
}
|
|
|
|
const categories: Category[] = [
|
|
{
|
|
id: 'work',
|
|
label: plugin.string.GettingWorkDone,
|
|
emojis: [
|
|
String.fromCodePoint(0x1f440),
|
|
String.fromCodePoint(0x2705),
|
|
String.fromCodePoint(0x274c),
|
|
String.fromCodePoint(0x2795),
|
|
String.fromCodePoint(0x2796),
|
|
String.fromCodePoint(0x2757),
|
|
String.fromCodePoint(0x0031, 0xfe0f, 0x20e3),
|
|
String.fromCodePoint(0x0032, 0xfe0f, 0x20e3),
|
|
String.fromCodePoint(0x0033, 0xfe0f, 0x20e3),
|
|
String.fromCodePoint(0x1f44b, 0x1f3fc),
|
|
String.fromCodePoint(0x1f44d, 0x1f3fc),
|
|
String.fromCodePoint(0x1f44c, 0x1f3fc)
|
|
],
|
|
icon: Work
|
|
},
|
|
{
|
|
id: 'smileys',
|
|
label: plugin.string.Smileys,
|
|
emojis: [...getEmojis(0x1f600, 0x1f64f), ...getEmojis(0x1f90c, 0x1f92f)],
|
|
icon: Emoji
|
|
},
|
|
{
|
|
id: 'nature',
|
|
label: plugin.string.Nature,
|
|
emojis: [
|
|
...getEmojis(0x1f408, 0x1f43e),
|
|
...getEmojis(0x1f980, 0x1f9ae),
|
|
...getEmojis(0x1f330, 0x1f343),
|
|
...getEmojis(0x1f300, 0x1f320),
|
|
...getEmojis(0x1f324, 0x1f32c, [0xfe0f]),
|
|
...getEmojis(0x2600, 0x2604, [0xfe0f])
|
|
],
|
|
icon: Nature
|
|
},
|
|
{
|
|
id: 'travels',
|
|
label: plugin.string.TravelAndPlaces,
|
|
emojis: [...getEmojis(0x1f5fb, 0x1f5ff), ...getEmojis(0x1f3e0, 0x1f3f0), ...getEmojis(0x1f680, 0x1f6a3)],
|
|
icon: Places
|
|
},
|
|
{
|
|
id: 'food',
|
|
label: plugin.string.Food,
|
|
emojis: [...getEmojis(0x1f345, 0x1f37f), ...getEmojis(0x1f32d, 0x1f32f)],
|
|
icon: Food
|
|
},
|
|
{
|
|
id: 'objects',
|
|
label: plugin.string.Objects,
|
|
emojis: [...getEmojis(0x1f4b6, 0x1f4fc)],
|
|
icon: Objects
|
|
},
|
|
{
|
|
id: 'symbols',
|
|
label: plugin.string.Symbols,
|
|
emojis: [
|
|
...getEmojis(0x00a9, 0x25fc, [0xfe0f]),
|
|
...getEmojis(0x2764, 0x2b07, [0xfe0f]),
|
|
...getEmojis(0x0023, 0x0039, [0xfe0f, 0x20e3]),
|
|
...getEmojis(0x1f532, 0x1f53d)
|
|
],
|
|
icon: Symbols
|
|
}
|
|
]
|
|
const dispatch = createEventDispatcher()
|
|
|
|
function handleScrollToCategory (categoryId: string) {
|
|
const el = document.getElementById(categoryId)
|
|
if (el) {
|
|
const next = el.nextElementSibling as HTMLElement
|
|
div.scroll(0, next.offsetTop - (currentFontSize === 'small-font' ? 14 : 16) * 1.75)
|
|
}
|
|
}
|
|
|
|
let currentCategory = categories[0]
|
|
function handleScrolled (catId?: CustomEvent) {
|
|
if (catId) {
|
|
const curCat = categories.find((it) => it.id === catId.detail[catId.detail.length - 1])
|
|
if (curCat) currentCategory = curCat
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<div class="antiPopup antiPopup-withHeader popup">
|
|
<div class="flex-row-center popup-header">
|
|
{#each categories as category}
|
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
<div
|
|
use:tooltip={{ label: category.label }}
|
|
class="element m-0-5"
|
|
class:selected={currentCategory === category}
|
|
on:click={() => handleScrollToCategory(category.id)}
|
|
>
|
|
<svelte:component this={category.icon} size={'large'} opacity={currentCategory === category ? '1' : '0.3'} />
|
|
</div>
|
|
{/each}
|
|
</div>
|
|
<div class="scrolling">
|
|
<Scroller bind:divScroll={div} on:scrolledCategories={handleScrolled} fade={emojiSP} noStretch>
|
|
{#each categories as category}
|
|
<div id={category.id} class="scroll-header categoryHeader">
|
|
<Label label={category.label} />
|
|
</div>
|
|
<div class="palette ml-3">
|
|
{#each category.emojis as emoji}
|
|
{#if emoji !== undefined}
|
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
<div class="element m-0-5" on:click={() => dispatch('close', emoji)}>{emoji}</div>
|
|
{/if}
|
|
{/each}
|
|
</div>
|
|
{/each}
|
|
</Scroller>
|
|
</div>
|
|
<div class="ap-space x2" />
|
|
</div>
|
|
|
|
<style lang="scss">
|
|
.popup {
|
|
height: 21.25rem;
|
|
}
|
|
.scrolling {
|
|
min-height: 0;
|
|
height: 16.5rem;
|
|
max-height: 16.5rem;
|
|
}
|
|
.popup-header {
|
|
margin: 0.75rem 0.75rem 0.5rem;
|
|
}
|
|
.scroll-header {
|
|
position: sticky;
|
|
top: 0;
|
|
margin: 0.75rem 0.75rem 0.25rem;
|
|
padding: 0.25rem 0.75rem;
|
|
font-size: 0.75rem;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
color: var(--dark-color);
|
|
background-color: var(--board-bg-color);
|
|
border-radius: 0.25rem;
|
|
&:first-child {
|
|
margin-top: 0;
|
|
}
|
|
}
|
|
.palette {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
width: 19.25rem;
|
|
font-size: 1.75rem;
|
|
}
|
|
.element {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
width: 2.5rem;
|
|
height: 2.5rem;
|
|
border-radius: 0.25rem;
|
|
color: var(--caption-color);
|
|
cursor: pointer;
|
|
|
|
&:hover {
|
|
background-color: var(--popup-bg-hover);
|
|
}
|
|
|
|
&.selected {
|
|
background-color: var(--popup-bg-hover);
|
|
}
|
|
}
|
|
</style>
|