Skip to content
This repository has been archived by the owner on Nov 26, 2024. It is now read-only.

Commit

Permalink
feat: add emoji picker
Browse files Browse the repository at this point in the history
  • Loading branch information
marekvospel committed Dec 24, 2023
1 parent 2a438eb commit 6749fb6
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 48 deletions.
99 changes: 54 additions & 45 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions services/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
},
"devDependencies": {
"@floating-ui/dom": "^1.5.3",
"@iconify-json/bx": "^1.1.7",
"@iconify-json/bxs": "^1.1.10",
"@iconify-json/twemoji": "^1.1.15",
"@matrix-org/olm": "^3.2.15",
"@rollup/plugin-wasm": "^6.2.2",
Expand All @@ -24,6 +26,7 @@
"@vospel/rehype-twemojify": "workspace:^",
"@vospel/svelte-utils": "workspace:^",
"debug": "^4.3.4",
"emojibase-data": "^15.3.0",
"highlight.js": "^11.9.0",
"matrix-encrypt-attachment": "^1.0.3",
"rehype-highlight": "^7.0.0",
Expand Down
28 changes: 28 additions & 0 deletions services/frontend/src/lib/components/message/EmojiPicker.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<script lang="ts">
import { createEventDispatcher } from "svelte";
import EmojiCategory from "./EmojiPicker/EmojiCategory.svelte";
import groups from 'emojibase-data/meta/groups.json'
const dispatch = createEventDispatcher()
let container: HTMLElement
function scrollToGroup(group: string) {
container.querySelector(`[data-group="${group}"]`)?.scrollIntoView({ behavior: 'smooth' })
}
</script>

<div class="flex flex-row gap-4 w-full max-h-75 overflow-y-auto relative rounded" bind:this={container}>
<div class="flex flex-col items-center gap-6 bg-surface2 h-full max-h-75 px-2 py-4 sticky top-0 overflow-y-auto">
{#each Object.keys(groups.groups) as group}
<button type="button" on:click={() => scrollToGroup(group)} class="flex items-center justify-center w-full h-full">
<span class="inline-block i-bxs:smile text-xl" />
</button>
{/each}
</div>
<div class="flex-col gap-8 w-full max-w-75">
{#each Object.keys(groups.groups) as group}
<EmojiCategory hiearchy={group} on:emoji={(emoji) => dispatch('emoji', emoji.detail)}/>
{/each}
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<script lang="ts">
import { createEventDispatcher } from 'svelte';
import emojis from 'emojibase-data/en/data.json'
import groups from 'emojibase-data/meta/groups.json'
const dispatch = createEventDispatcher()
export let hiearchy: string = '0'
let open = true
</script>

<details bind:open={open} data-group={hiearchy}>
<summary class="marker:content-none flex flex-row gap-1 items-center text-subtext0 hover:text-text duration-300 transition-colors">
<span class="i-bxs:smile inline-block" />
<span>Category</span>
<span class="i-bx:chevron-down inline-block {open ? '' : 'rotate-180'}"/>
</summary>

<div class="flex flex-row items-center flex-wrap gap-2 pt-2">
{#each emojis.filter((e) => e.subgroup !== undefined && groups.hierarchy[hiearchy]?.includes(e.subgroup)).sort((a, b) => (a.order ?? 0) - (b.order ?? 0)) as emoji}
<button type="button" on:click={() => dispatch('emoji', emoji.emoji)}>
<img src="https://cdn.jsdelivr.net/gh/twitter/[email protected]/assets/svg/{emoji.hexcode.toLowerCase()}.svg" class="block w-8 h-8 overflow-hidden" alt={emoji.emoji}>
</button>
{/each}
</div>
</details>
59 changes: 59 additions & 0 deletions services/frontend/src/lib/components/popper/SveltePopper.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<script lang="ts">
import { computePosition } from '@floating-ui/dom'
import { onMount, tick } from 'svelte';
export let open = false
let component: HTMLElement | undefined
let tooltip: HTMLElement | undefined
onMount(updatePosition)
$: {
open
tick().then(() => {
updatePosition()
})
}
function updatePosition() {
if (!component || !tooltip) return
computePosition(component, tooltip, {
placement: 'top',
strategy: 'absolute',
}).then((position) => {
if (!tooltip) return
tooltip.style.left = `min(${position.x}px, calc(100% - 1rem - ${tooltip.clientWidth}px)`
tooltip.style.top = `calc(${position.y}px - 1rem)`
})
}
function click(event: MouseEvent) {
if (component && component.contains(event.target as Node)) return
if (tooltip && tooltip.contains(event.target as Node)) return
open = false
}
</script>

<svelte:body on:click={click}/>

<div bind:this={component} on:click={() => open = !open} on:keypress={() => open = !open} role="button" tabindex="0">
<slot open={open} />
</div>
{#if open}
<div bind:this={tooltip} class="tooltip">
<slot name="tooltip" />
</div>
{/if}

<style>
.tooltip {
@apply w-max absolute left-0 top-0 bg-surface1 rounded;
}
</style>
11 changes: 8 additions & 3 deletions services/frontend/src/lib/views/AppView.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import MessageEvent from '$lib/components/message/MessageEvent.svelte'
import { appState } from '$lib/app-state';
import type { MatrixEvent } from 'matrix-js-sdk';
import SveltePopper from '$lib/components/popper/SveltePopper.svelte';
import EmojiPicker from '$lib/components/message/EmojiPicker.svelte';
let message = ''
Expand Down Expand Up @@ -62,9 +64,12 @@
<form class="w-full sticky bottom-0 flex px-4 py-4 bg-base" on:submit|preventDefault={send}>
<div class="w-full flex flex-row gap-2 bg-surface0 border border-surface1 rounded-xl p-2">
<textarea bind:value={message} on:keydown={keydownSend} placeholder="Message" class="w-full resize-none bg-transparent border-none h-[1.5em] outline-none" />
<button type="button" class="aspect-square flex flex-row items-center filter-grayscale focus:filter-grayscale-0 hover:filter-grayscale-0 transition-all duration-300">
<span class="inline-block i-twemoji:face-with-tears-of-joy text-xl" />
</button>
<SveltePopper let:open>
<button type="button" class="aspect-square flex flex-row items-center filter-grayscale focus-visible:filter-grayscale-0 hover:filter-grayscale-0 transition-all duration-300 { open ? '!filter-grayscale-0' : ''}">
<span class="inline-block i-twemoji:face-with-tears-of-joy text-xl" />
</button>
<EmojiPicker slot="tooltip" on:emoji={(emoji) => message += emoji.detail } />
</SveltePopper>
<button type="submit" class="flex flex-row items-center hover:text-teal focus:text-teal transition-colors duration-300">
<span class="inline-block i-bx:send text-2xl" />
</button>
Expand Down

0 comments on commit 6749fb6

Please sign in to comment.