Merge pull request #4706 from h3poteto/iss-4653/post-with-emoji
refs #4653 Add emoji picker in compose
This commit is contained in:
commit
7ac9a17b7d
|
@ -14,11 +14,13 @@
|
|||
"thirdparty": "license-checker --production --json > thirdparty.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@emoji-mart/react": "^1.1.1",
|
||||
"blurhash": "^2.0.5",
|
||||
"dayjs": "^1.11.10",
|
||||
"dexie": "^3.2.4",
|
||||
"electron-serve": "^1.1.0",
|
||||
"electron-store": "^8.1.0",
|
||||
"emoji-mart": "^5.5.2",
|
||||
"flowbite": "^2.0.0",
|
||||
"flowbite-react": "^0.6.4",
|
||||
"megalodon": "^9.1.1",
|
||||
|
|
|
@ -1,9 +1,24 @@
|
|||
import { Button, Checkbox, Dropdown, Label, Radio, Select, Spinner, TextInput, Textarea, ToggleSwitch } from 'flowbite-react'
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
CustomFlowbiteTheme,
|
||||
Dropdown,
|
||||
Flowbite,
|
||||
Label,
|
||||
Radio,
|
||||
Select,
|
||||
Spinner,
|
||||
TextInput,
|
||||
Textarea,
|
||||
ToggleSwitch
|
||||
} from 'flowbite-react'
|
||||
import { ChangeEvent, Dispatch, SetStateAction, useEffect, useRef, useState } from 'react'
|
||||
import { FormattedMessage, useIntl } from 'react-intl'
|
||||
import { FaEnvelope, FaGlobe, FaListCheck, FaLock, FaLockOpen, FaPaperPlane, FaPaperclip, FaXmark } from 'react-icons/fa6'
|
||||
import { FaEnvelope, FaFaceLaughBeam, FaGlobe, FaListCheck, FaLock, FaLockOpen, FaPaperPlane, FaPaperclip, FaXmark } from 'react-icons/fa6'
|
||||
import { Entity, MegalodonInterface } from 'megalodon'
|
||||
import { useToast } from '@/utils/toast'
|
||||
import Picker from '@emoji-mart/react'
|
||||
import { data } from '@/utils/emojiData'
|
||||
|
||||
type Props = {
|
||||
client: MegalodonInterface
|
||||
|
@ -16,6 +31,17 @@ type Poll = {
|
|||
multiple: boolean
|
||||
}
|
||||
|
||||
const customTheme: CustomFlowbiteTheme = {
|
||||
dropdown: {
|
||||
content: 'focus:outline-none',
|
||||
floating: {
|
||||
item: {
|
||||
base: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default function Compose(props: Props) {
|
||||
const [body, setBody] = useState('')
|
||||
const [visibility, setVisibility] = useState<'public' | 'unlisted' | 'private' | 'direct'>('public')
|
||||
|
@ -128,6 +154,16 @@ export default function Compose(props: Props) {
|
|||
}
|
||||
}
|
||||
|
||||
const onEmojiSelect = emoji => {
|
||||
const textarea = document.getElementById('body') as HTMLTextAreaElement
|
||||
const cursor = textarea.selectionStart
|
||||
if (emoji.native) {
|
||||
setBody(current => `${current.slice(0, cursor)}${emoji.native} ${current.slice(cursor)}`)
|
||||
} else if (emoji.shortcodes) {
|
||||
setBody(current => `${current.slice(0, cursor)}${emoji.shortcodes} ${current.slice(cursor)}`)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="px-4 pb-4">
|
||||
<form id="form">
|
||||
|
@ -142,14 +178,31 @@ export default function Compose(props: Props) {
|
|||
placeholder={formatMessage({ id: 'compose.spoiler.placeholder' })}
|
||||
/>
|
||||
)}
|
||||
<Textarea
|
||||
id="body"
|
||||
className="resize-none focus:ring-0"
|
||||
placeholder={formatMessage({ id: 'compose.placeholder' })}
|
||||
rows={3}
|
||||
value={body}
|
||||
onChange={ev => setBody(ev.target.value)}
|
||||
/>
|
||||
<div className="relative">
|
||||
<Textarea
|
||||
id="body"
|
||||
className="resize-none focus:ring-0"
|
||||
placeholder={formatMessage({ id: 'compose.placeholder' })}
|
||||
rows={3}
|
||||
value={body}
|
||||
onChange={ev => setBody(ev.target.value)}
|
||||
/>
|
||||
<Flowbite theme={{ theme: customTheme }}>
|
||||
<Dropdown
|
||||
label=""
|
||||
dismissOnClick
|
||||
renderTrigger={() => (
|
||||
<span className="absolute top-1 right-1 text-gray-600 cursor-pointer">
|
||||
<FaFaceLaughBeam />
|
||||
</span>
|
||||
)}
|
||||
>
|
||||
<Dropdown.Item>
|
||||
<Picker data={data} onEmojiSelect={onEmojiSelect} previewPosition="none" set="native" perLine="7" theme="light" />
|
||||
</Dropdown.Item>
|
||||
</Dropdown>
|
||||
</Flowbite>
|
||||
</div>
|
||||
</form>
|
||||
{poll && <PollForm poll={poll} setPoll={setPoll} />}
|
||||
<div className="attachments flex gap-2">
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
export const data = async () => {
|
||||
const response = await fetch('https://cdn.jsdelivr.net/npm/@emoji-mart/data')
|
||||
|
||||
return response.json()
|
||||
}
|
10
yarn.lock
10
yarn.lock
|
@ -1092,6 +1092,11 @@
|
|||
minimatch "^3.0.4"
|
||||
plist "^3.0.4"
|
||||
|
||||
"@emoji-mart/react@^1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@emoji-mart/react/-/react-1.1.1.tgz#ddad52f93a25baf31c5383c3e7e4c6e05554312a"
|
||||
integrity sha512-NMlFNeWgv1//uPsvLxvGQoIerPuVdXwK/EUek8OOkJ6wVOWPUizRBJU0hDqWZCOROVpfBgCemaC3m6jDOXi03g==
|
||||
|
||||
"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0":
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
|
||||
|
@ -2786,6 +2791,11 @@ electron@^27.0.0:
|
|||
"@types/node" "^18.11.18"
|
||||
extract-zip "^2.0.1"
|
||||
|
||||
emoji-mart@^5.5.2:
|
||||
version "5.5.2"
|
||||
resolved "https://registry.yarnpkg.com/emoji-mart/-/emoji-mart-5.5.2.tgz#3ddbaf053139cf4aa217650078bc1c50ca8381af"
|
||||
integrity sha512-Sqc/nso4cjxhOwWJsp9xkVm8OF5c+mJLZJFoFfzRuKO+yWiN7K8c96xmtughYb0d/fZ8UC6cLIQ/p4BR6Pv3/A==
|
||||
|
||||
emoji-regex@^8.0.0:
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
|
||||
|
|
Loading…
Reference in New Issue