forked from Mirrors/gomuks
parent
152942663f
commit
1b0a8d6192
3 changed files with 36 additions and 3 deletions
|
@ -90,6 +90,7 @@ export const EmojiGroup = ({
|
||||||
ref={divRef}
|
ref={divRef}
|
||||||
className="emoji-category"
|
className="emoji-category"
|
||||||
id={`emoji-category-${categoryID}`}
|
id={`emoji-category-${categoryID}`}
|
||||||
|
data-category-id={categoryID}
|
||||||
style={{ containIntrinsicHeight: `${1.5 + Math.ceil(emojis.length / 8) * 2.5}rem` }}
|
style={{ containIntrinsicHeight: `${1.5 + Math.ceil(emojis.length / 8) * 2.5}rem` }}
|
||||||
>
|
>
|
||||||
<h4 className="emoji-category-name">
|
<h4 className="emoji-category-name">
|
||||||
|
|
|
@ -90,6 +90,11 @@ div.emoji-picker {
|
||||||
border-bottom-left-radius: 0;
|
border-bottom-left-radius: 0;
|
||||||
border-bottom-right-radius: 0;
|
border-bottom-right-radius: 0;
|
||||||
border-bottom: 2px solid transparent;
|
border-bottom: 2px solid transparent;
|
||||||
|
|
||||||
|
&.visible {
|
||||||
|
border-bottom: 2px solid var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
border-bottom: 2px solid var(--primary-color-dark);
|
border-bottom: 2px solid var(--primary-color-dark);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU Affero General Public License
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
import React, { CSSProperties, JSX, use, useCallback, useState } from "react"
|
import React, { CSSProperties, JSX, use, useCallback, useEffect, useRef, useState } from "react"
|
||||||
import { getMediaURL } from "@/api/media.ts"
|
import { getMediaURL } from "@/api/media.ts"
|
||||||
import { RoomStateStore, useCustomEmojis } from "@/api/statestore"
|
import { RoomStateStore, useCustomEmojis } from "@/api/statestore"
|
||||||
import { roomStateGUIDToString } from "@/api/types"
|
import { roomStateGUIDToString } from "@/api/types"
|
||||||
|
@ -64,6 +64,8 @@ const EmojiPicker = ({ style, selected, onSelect, room, allowFreeform, closeOnSe
|
||||||
const client = use(ClientContext)!
|
const client = use(ClientContext)!
|
||||||
const [query, setQuery] = useState("")
|
const [query, setQuery] = useState("")
|
||||||
const [previewEmoji, setPreviewEmoji] = useState<Emoji>()
|
const [previewEmoji, setPreviewEmoji] = useState<Emoji>()
|
||||||
|
const emojiCategoryBarRef = useRef<HTMLDivElement>(null)
|
||||||
|
const emojiListRef = useRef<HTMLDivElement>(null)
|
||||||
const watchedEmojiPackKeys = client.store.getEmojiPackKeys().map(roomStateGUIDToString)
|
const watchedEmojiPackKeys = client.store.getEmojiPackKeys().map(roomStateGUIDToString)
|
||||||
const customEmojiPacks = useCustomEmojis(client.store, room)
|
const customEmojiPacks = useCustomEmojis(client.store, room)
|
||||||
const emojis = useFilteredEmojis(query, {
|
const emojis = useFilteredEmojis(query, {
|
||||||
|
@ -89,8 +91,33 @@ const EmojiPicker = ({ style, selected, onSelect, room, allowFreeform, closeOnSe
|
||||||
const categoryID = evt.currentTarget.getAttribute("data-category-id")!
|
const categoryID = evt.currentTarget.getAttribute("data-category-id")!
|
||||||
document.getElementById(`emoji-category-${categoryID}`)?.scrollIntoView()
|
document.getElementById(`emoji-category-${categoryID}`)?.scrollIntoView()
|
||||||
}, [])
|
}, [])
|
||||||
|
useEffect(() => {
|
||||||
|
const cats = emojiCategoryBarRef.current
|
||||||
|
const lists = emojiListRef.current
|
||||||
|
if (!cats || !lists) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const observer = new IntersectionObserver(entries => {
|
||||||
|
for (const entry of entries) {
|
||||||
|
const catID = entry.target.getAttribute("data-category-id")
|
||||||
|
const cat = catID && cats.querySelector(`.emoji-category-icon[data-category-id="${catID}"]`)
|
||||||
|
if (!cat) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
cat.classList.add("visible")
|
||||||
|
} else {
|
||||||
|
cat.classList.remove("visible")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
for (const cat of lists.getElementsByClassName("emoji-category")) {
|
||||||
|
observer.observe(cat)
|
||||||
|
}
|
||||||
|
return () => observer.disconnect()
|
||||||
|
}, [])
|
||||||
return <div className="emoji-picker" style={style}>
|
return <div className="emoji-picker" style={style}>
|
||||||
<div className="emoji-category-bar">
|
<div className="emoji-category-bar" ref={emojiCategoryBarRef}>
|
||||||
<button
|
<button
|
||||||
className="emoji-category-icon"
|
className="emoji-category-icon"
|
||||||
data-category-id={CATEGORY_FREQUENTLY_USED}
|
data-category-id={CATEGORY_FREQUENTLY_USED}
|
||||||
|
@ -132,7 +159,7 @@ const EmojiPicker = ({ style, selected, onSelect, room, allowFreeform, closeOnSe
|
||||||
</div>
|
</div>
|
||||||
<div className="emoji-list">
|
<div className="emoji-list">
|
||||||
{/* Chrome is dumb and doesn't allow scrolling without an inner div */}
|
{/* Chrome is dumb and doesn't allow scrolling without an inner div */}
|
||||||
<div className="emoji-list-inner">
|
<div className="emoji-list-inner" ref={emojiListRef}>
|
||||||
{emojis.map(group => {
|
{emojis.map(group => {
|
||||||
if (!group?.length) {
|
if (!group?.length) {
|
||||||
return null
|
return null
|
||||||
|
|
Loading…
Add table
Reference in a new issue