feat: GIF search (Klipy), stickers, emoji picker, and bug fixes
- Add GIF search powered by Klipy API with correct response mapping (file.sm/hd tiers, not flat files structure) - Add sticker system: packs, upload with auto-downscale, send in messages - Add tabbed InputPopover with emoji, GIF, and sticker pickers - Fix GIF API key migration race condition (column-add loop vs rename) - Fix masked API key corruption on settings save (server + client guards) - Fix sticker packs 403 (reversed isMember parameter order) - Fix emoji picker not filling popover width (perLine 8→9, CSS 100%) - Add error logging for Klipy API failures
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
import Picker from '@emoji-mart/react';
|
||||
import data from '@emoji-mart/data';
|
||||
|
||||
interface EmojiPickerProps {
|
||||
onEmojiSelect: (emoji: { native: string }) => void;
|
||||
}
|
||||
|
||||
export function EmojiPicker({ onEmojiSelect }: EmojiPickerProps) {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// Prevent keyboard events from bubbling out (e.g. Enter submitting the chat input)
|
||||
useEffect(() => {
|
||||
const el = containerRef.current;
|
||||
if (!el) return;
|
||||
const stop = (e: KeyboardEvent) => e.stopPropagation();
|
||||
el.addEventListener('keydown', stop);
|
||||
return () => el.removeEventListener('keydown', stop);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div ref={containerRef} className="emoji-picker-wrapper">
|
||||
<Picker
|
||||
data={data}
|
||||
onEmojiSelect={onEmojiSelect}
|
||||
theme="dark"
|
||||
set="native"
|
||||
skinTonePosition="search"
|
||||
previewPosition="none"
|
||||
navPosition="bottom"
|
||||
perLine={9}
|
||||
maxFrequentRows={2}
|
||||
emojiSize={24}
|
||||
emojiButtonSize={32}
|
||||
categories={['frequent', 'people', 'nature', 'foods', 'activity', 'places', 'objects', 'symbols', 'flags']}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user