// gomuks - A Matrix client written in Go.
// Copyright (C) 2024 Tulir Asokan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
import { CSSProperties, JSX, use, useCallback, useState } from "react"
import { getMediaURL } from "@/api/media.ts"
import { CATEGORY_FREQUENTLY_USED, Emoji, PartialEmoji, categories, useFilteredEmojis } from "@/util/emoji"
import { ClientContext } from "../ClientContext.ts"
import { ModalCloseContext } from "../modal/Modal.tsx"
import CloseIcon from "@/icons/close.svg?react"
import ActivitiesIcon from "@/icons/emoji-categories/activities.svg?react"
import AnimalsNatureIcon from "@/icons/emoji-categories/animals-nature.svg?react"
import FlagsIcon from "@/icons/emoji-categories/flags.svg?react"
import FoodBeverageIcon from "@/icons/emoji-categories/food-beverage.svg?react"
import ObjectsIcon from "@/icons/emoji-categories/objects.svg?react"
import PeopleBodyIcon from "@/icons/emoji-categories/people-body.svg?react"
import SmileysEmotionIcon from "@/icons/emoji-categories/smileys-emotion.svg?react"
import SymbolsIcon from "@/icons/emoji-categories/symbols.svg?react"
import TravelPlacesIcon from "@/icons/emoji-categories/travel-places.svg?react"
import RecentIcon from "@/icons/schedule.svg?react"
import SearchIcon from "@/icons/search.svg?react"
import "./EmojiPicker.css"
interface EmojiCategory {
index: number
name?: string
icon: JSX.Element
}
const sortedEmojiCategories: EmojiCategory[] = [
{ index: 7, icon: },
{ index: 6, icon: },
{ index: 1, icon: },
{ index: 4, icon: },
{ index: 9, icon: },
{ index: 0, icon: },
{ index: 5, icon: },
{ index: 8, icon: },
{ index: 3, icon: },
]
function renderEmoji(emoji: Emoji): JSX.Element | string {
if (emoji.u.startsWith("mxc://")) {
return
}
return emoji.u
}
interface EmojiPickerProps {
style: CSSProperties
onSelect: (emoji: PartialEmoji, isSelected?: boolean) => void
allowFreeform?: boolean
closeOnSelect?: boolean
selected?: string[]
}
export const EmojiPicker = ({ style, selected, onSelect, allowFreeform, closeOnSelect }: EmojiPickerProps) => {
const client = use(ClientContext)!
const [query, setQuery] = useState("")
const emojis = useFilteredEmojis(query, {
frequentlyUsed: client.store.frequentlyUsedEmoji,
frequentlyUsedAsCategory: true,
})
const [previewEmoji, setPreviewEmoji] = useState()
const clearQuery = useCallback(() => setQuery(""), [])
const cats: JSX.Element[] = []
let currentCat: JSX.Element[] = []
let currentCatNum: number | string = -1
const close = use(ModalCloseContext)
const onSelectWrapped = (emoji: PartialEmoji) => {
onSelect(emoji, selected?.includes(emoji.u))
if (emoji.c) {
client.incrementFrequentlyUsedEmoji(emoji.u)
.catch(err => console.error("Failed to increment frequently used emoji", err))
}
if (closeOnSelect) {
close()
}
}
for (const emoji of emojis) {
if (emoji.c === 2) {
continue
}
if (emoji.c !== currentCatNum) {
if (currentCat.length) {
const categoryName = typeof currentCatNum === "number" ? categories[currentCatNum] : currentCatNum
cats.push(