From ededafa8de59ca31cd03c7a96efb7783b23b15d0 Mon Sep 17 00:00:00 2001 From: Chad Curtis Date: Wed, 4 Mar 2026 03:37:52 -0600 Subject: [PATCH] Merge emoji and GIF into single tabbed picker in ComposeBox --- src/components/ComposeBox.tsx | 154 ++++++++++++++++++---------------- src/components/GifPicker.tsx | 2 +- 2 files changed, 82 insertions(+), 74 deletions(-) diff --git a/src/components/ComposeBox.tsx b/src/components/ComposeBox.tsx index 3c56b3fb..d646ca87 100644 --- a/src/components/ComposeBox.tsx +++ b/src/components/ComposeBox.tsx @@ -1,6 +1,6 @@ import { useState, useRef, useCallback, useMemo, useEffect } from 'react'; import { Link } from 'react-router-dom'; -import { Paperclip, Smile, AlertTriangle, X, Loader2, ImagePlay, Mic, Square } from 'lucide-react'; +import { Paperclip, Smile, AlertTriangle, X, Loader2, Mic, Square } from 'lucide-react'; import { nip19 } from 'nostr-tools'; import { encode as blurhashEncode } from 'blurhash'; import type { NostrEvent } from '@nostrify/nostrify'; @@ -174,8 +174,8 @@ export function ComposeBox({ const [expanded, setExpanded] = useState(false); const [cwEnabled, setCwEnabled] = useState(false); const [cwText, setCwText] = useState(''); - const [emojiOpen, setEmojiOpen] = useState(false); - const [gifOpen, setGifOpen] = useState(false); + const [pickerOpen, setPickerOpen] = useState(false); + const [pickerTab, setPickerTab] = useState<'emoji' | 'gif'>('emoji'); const [internalPreviewMode, setInternalPreviewMode] = useState(false); const [removedEmbeds, setRemovedEmbeds] = useState>(new Set()); const [_uploadedFileTags, setUploadedFileTags] = useState([]); @@ -1176,76 +1176,84 @@ export function ComposeBox({ )} - {/* Emoji picker */} - - - - - - - - {!emojiOpen && Emoji} - - - { - if (selection.type === 'native') { - insertEmoji(selection.emoji); - } else { - insertEmoji(`:${selection.shortcode}:`); - } - }} - /> - - - - {/* GIF picker */} - - - - - - - - {!gifOpen && GIF} - - - { - setContent((prev) => (prev ? prev + '\n' + gif.url : gif.url)); - setGifOpen(false); - expand(); - }} /> - - + {/* Emoji / GIF picker */} + + + + + + + + {!pickerOpen && Emoji / GIF} + + + {/* Tab bar */} +
+ + +
+ {/* Picker content */} + {pickerTab === 'emoji' ? ( + { + if (selection.type === 'native') { + insertEmoji(selection.emoji); + } else { + insertEmoji(`:${selection.shortcode}:`); + } + }} + /> + ) : ( + { + setContent((prev) => (prev ? prev + '\n' + gif.url : gif.url)); + setPickerOpen(false); + expand(); + }} /> + )} +
+
{/* Content warning (NIP-36) */} diff --git a/src/components/GifPicker.tsx b/src/components/GifPicker.tsx index 52fccdf0..819a08c4 100644 --- a/src/components/GifPicker.tsx +++ b/src/components/GifPicker.tsx @@ -118,7 +118,7 @@ export function GifPicker({ onSelect }: GifPickerProps) { }, [onSelect]); return ( -
+
{/* Search input */}