feat: add emoji picker to post editor

This commit is contained in:
codytseng
2025-05-27 22:39:57 +08:00
parent 061e38a78f
commit 9edd61db78
4 changed files with 78 additions and 9 deletions

View File

@@ -12,6 +12,7 @@ import {
RefObject,
useContext,
useEffect,
useRef,
useState
} from 'react'
import ExplorePage from './pages/primary/ExplorePage'
@@ -90,6 +91,7 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) {
const [secondaryStack, setSecondaryStack] = useState<TStackItem[]>([])
const [isShared, setIsShared] = useState(false)
const { isSmallScreen } = useScreenSize()
const ignorePopStateRef = useRef(false)
useEffect(() => {
window.history.pushState(null, '', window.location.href)
@@ -118,8 +120,14 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) {
}
const onPopState = (e: PopStateEvent) => {
if (ignorePopStateRef.current) {
ignorePopStateRef.current = false
return
}
const closeModal = modalManager.pop()
if (closeModal) {
ignorePopStateRef.current = true
window.history.forward()
return
}

View File

@@ -0,0 +1,51 @@
import { Drawer, DrawerContent, DrawerTrigger } from '@/components/ui/drawer'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuTrigger
} from '@/components/ui/dropdown-menu'
import { useScreenSize } from '@/providers/ScreenSizeProvider'
import { useState } from 'react'
import EmojiPicker from '../EmojiPicker'
export default function EmojiPickerDialog({
children,
onEmojiClick
}: {
children: React.ReactNode
onEmojiClick?: (emoji: string) => void
}) {
const { isSmallScreen } = useScreenSize()
const [open, setOpen] = useState(false)
if (isSmallScreen) {
return (
<Drawer open={open} onOpenChange={setOpen}>
<DrawerTrigger asChild>{children}</DrawerTrigger>
<DrawerContent>
<EmojiPicker
onEmojiClick={(data) => {
setOpen(false)
onEmojiClick?.(data.emoji)
}}
/>
</DrawerContent>
</Drawer>
)
}
return (
<DropdownMenu open={open} onOpenChange={setOpen}>
<DropdownMenuTrigger asChild>{children}</DropdownMenuTrigger>
<DropdownMenuContent side="top" className="p-0 w-fit">
<EmojiPicker
onEmojiClick={(data, e) => {
e.stopPropagation()
setOpen(false)
onEmojiClick?.(data.emoji)
}}
/>
</DropdownMenuContent>
</DropdownMenu>
)
}

View File

@@ -5,10 +5,11 @@ import { useToast } from '@/hooks/use-toast'
import { createCommentDraftEvent, createShortTextNoteDraftEvent } from '@/lib/draft-event'
import { useNostr } from '@/providers/NostrProvider'
import postContentCache from '@/services/post-content-cache.service'
import { ChevronDown, ImageUp, LoaderCircle } from 'lucide-react'
import { ImageUp, LoaderCircle, Settings, Smile } from 'lucide-react'
import { Event, kinds } from 'nostr-tools'
import { useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import EmojiPickerDialog from '../EmojiPickerDialog'
import Mentions from './Mentions'
import { usePostEditor } from './PostEditorProvider'
import PostOptions from './PostOptions'
@@ -88,7 +89,7 @@ export default function PostContent({
}
return (
<div className="space-y-4">
<div className="space-y-2">
{parentEvent && (
<ScrollArea className="flex max-h-48 flex-col overflow-y-auto rounded-lg border bg-muted/40">
<div className="p-2 sm:p-3 pointer-events-none">
@@ -120,19 +121,22 @@ export default function PostContent({
}
accept="image/*,video/*,audio/*"
>
<Button variant="secondary" disabled={uploadingFiles > 0}>
<Button variant="ghost" size="icon" disabled={uploadingFiles > 0}>
{uploadingFiles > 0 ? <LoaderCircle className="animate-spin" /> : <ImageUp />}
</Button>
</Uploader>
<EmojiPickerDialog onEmojiClick={(emoji) => textareaRef.current?.insertText(emoji)}>
<Button variant="ghost" size="icon">
<Smile />
</Button>
</EmojiPickerDialog>
<Button
variant="link"
className="text-foreground gap-0 px-0"
variant="ghost"
size="icon"
className={showMoreOptions ? 'bg-accent' : ''}
onClick={() => setShowMoreOptions((pre) => !pre)}
>
{t('More options')}
<ChevronDown
className={`transition-transform ${showMoreOptions ? 'rotate-180' : ''}`}
/>
<Settings />
</Button>
</div>
<div className="flex gap-2 items-center">

View File

@@ -19,6 +19,7 @@ import suggestion from './suggestion'
export type TPostTextareaHandle = {
appendText: (text: string) => void
insertText: (text: string) => void
}
const PostTextarea = forwardRef<
@@ -94,6 +95,11 @@ const PostTextarea = forwardRef<
.insertContent(text)
.run()
}
},
insertText: (text: string) => {
if (editor) {
editor.chain().focus().insertContent(text).run()
}
}
}))