diff --git a/package.json b/package.json index 0055dd54..1dafa612 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,8 @@ "**/*": "prettier --write --ignore-unknown" }, "dependencies": { + "@emoji-mart/data": "^1.1.2", + "@emoji-mart/react": "^1.1.1", "@radix-ui/react-collapsible": "^1.0.2", "@radix-ui/react-dialog": "^1.0.3", "@radix-ui/react-dropdown-menu": "^2.0.4", @@ -28,6 +30,7 @@ "boring-avatars": "^1.7.0", "dayjs": "^1.11.7", "destr": "^1.2.2", + "emoji-mart": "^5.5.2", "framer-motion": "^9.1.7", "jotai": "^2.0.3", "jotai-cache": "^0.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c208038d..61af48ee 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,6 +1,8 @@ lockfileVersion: 5.4 specifiers: + '@emoji-mart/data': ^1.1.2 + '@emoji-mart/react': ^1.1.1 '@radix-ui/react-collapsible': ^1.0.2 '@radix-ui/react-dialog': ^1.0.3 '@radix-ui/react-dropdown-menu': ^2.0.4 @@ -27,6 +29,7 @@ specifiers: csstype: ^3.1.1 dayjs: ^1.11.7 destr: ^1.2.2 + emoji-mart: ^5.5.2 eslint: ^8.36.0 eslint-config-next: ^13.2.4 eslint-config-prettier: ^8.8.0 @@ -58,6 +61,8 @@ specifiers: ws: ^8.13.0 dependencies: + '@emoji-mart/data': 1.1.2 + '@emoji-mart/react': 1.1.1_kyrnz3vmphzqyjjk2ivrm6bcsu '@radix-ui/react-collapsible': 1.0.2_biqbaboplfbrettd7655fr4n2y '@radix-ui/react-dialog': 1.0.3_aen5vu2fkbnw3ssyd5drxdxkh4 '@radix-ui/react-dropdown-menu': 2.0.4_aen5vu2fkbnw3ssyd5drxdxkh4 @@ -74,6 +79,7 @@ dependencies: boring-avatars: 1.7.0 dayjs: 1.11.7 destr: 1.2.2 + emoji-mart: 5.5.2 framer-motion: 9.1.7_biqbaboplfbrettd7655fr4n2y jotai: 2.0.3_react@18.2.0 jotai-cache: 0.3.0_jotai@2.0.3 @@ -375,6 +381,22 @@ packages: '@babel/helper-validator-identifier': 7.19.1 to-fast-properties: 2.0.0 + /@emoji-mart/data/1.1.2: + resolution: + { integrity: sha512-1HP8BxD2azjqWJvxIaWAMyTySeZY0Osr83ukYjltPVkNXeJvTz7yDrPLBtnrD5uqJ3tg4CcLuuBW09wahqL/fg== } + dev: false + + /@emoji-mart/react/1.1.1_kyrnz3vmphzqyjjk2ivrm6bcsu: + resolution: + { integrity: sha512-NMlFNeWgv1//uPsvLxvGQoIerPuVdXwK/EUek8OOkJ6wVOWPUizRBJU0hDqWZCOROVpfBgCemaC3m6jDOXi03g== } + peerDependencies: + emoji-mart: ^5.2 + react: ^16.8 || ^17 || ^18 + dependencies: + emoji-mart: 5.5.2 + react: 18.2.0 + dev: false + /@emotion/is-prop-valid/0.8.8: resolution: { integrity: sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA== } @@ -2511,6 +2533,11 @@ packages: resolution: { integrity: sha512-zx8hqumOqltKsv/MF50yvdAlPF9S/4PXbyfzJS6ZGhbddGkRegdwImmfSVqCkEziYzrIGZ/TlrzBND4FysfkDg== } + /emoji-mart/5.5.2: + resolution: + { integrity: sha512-Sqc/nso4cjxhOwWJsp9xkVm8OF5c+mJLZJFoFfzRuKO+yWiN7K8c96xmtughYb0d/fZ8UC6cLIQ/p4BR6Pv3/A== } + dev: false + /emoji-regex/8.0.0: resolution: { integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== } diff --git a/src/assets/icons/emoji.tsx b/src/assets/icons/emoji.tsx new file mode 100644 index 00000000..9dc35379 --- /dev/null +++ b/src/assets/icons/emoji.tsx @@ -0,0 +1,18 @@ +export default function EmojiIcon({ className }: { className: string }) { + return ( + + + + ); +} diff --git a/src/assets/icons/image.tsx b/src/assets/icons/image.tsx new file mode 100644 index 00000000..ffc0c596 --- /dev/null +++ b/src/assets/icons/image.tsx @@ -0,0 +1,18 @@ +export default function ImageIcon({ className }: { className: string }) { + return ( + + + + ); +} diff --git a/src/components/note/form/basic.tsx b/src/components/form/base.tsx similarity index 73% rename from src/components/note/form/basic.tsx rename to src/components/form/base.tsx index a44a49ae..fe4e8021 100644 --- a/src/components/note/form/basic.tsx +++ b/src/components/form/base.tsx @@ -1,14 +1,19 @@ +import EmojiPicker from '@components/form/emojiPicker'; import { RelayContext } from '@components/relaysProvider'; import { activeAccountAtom } from '@stores/account'; +import { noteContentAtom } from '@stores/note'; import { relaysAtom } from '@stores/relays'; import { dateToUnix } from '@utils/getDate'; +import ImageIcon from '@assets/icons/image'; + import * as Dialog from '@radix-ui/react-dialog'; import { SizeIcon } from '@radix-ui/react-icons'; import * as commands from '@uiw/react-md-editor/lib/commands'; import { useAtom, useAtomValue } from 'jotai'; +import { useResetAtom } from 'jotai/utils'; import dynamic from 'next/dynamic'; import { getEventHash, signEvent } from 'nostr-tools'; import { useContext, useState } from 'react'; @@ -17,14 +22,15 @@ const MDEditor = dynamic(() => import('@uiw/react-md-editor').then((mod) => mod. ssr: false, }); -export default function FormBasic() { +export default function FormBase() { const pool: any = useContext(RelayContext); const relays = useAtomValue(relaysAtom); const [activeAccount] = useAtom(activeAccountAtom); + const [value, setValue] = useAtom(noteContentAtom); + const resetValue = useResetAtom(noteContentAtom); const [open, setOpen] = useState(false); - const [value, setValue] = useState(''); const pubkey = activeAccount.id; const privkey = activeAccount.privkey; @@ -41,7 +47,7 @@ export default function FormBasic() { event.sig = signEvent(event, privkey); pool.publish(event, relays); - setValue(''); + resetValue; }; const postButton = { @@ -49,9 +55,9 @@ export default function FormBasic() { keyCommand: 'post', buttonProps: { className: 'cta-btn', 'aria-label': 'Post a message' }, icon: ( - + ), execute: (state: { text: any }) => { if (state.text > 0) { @@ -82,37 +88,9 @@ export default function FormBasic() {
+ - - - - - - - - +
diff --git a/src/components/note/form/comment.tsx b/src/components/form/comment.tsx similarity index 94% rename from src/components/note/form/comment.tsx rename to src/components/form/comment.tsx index 6a192e78..35513020 100644 --- a/src/components/note/form/comment.tsx +++ b/src/components/form/comment.tsx @@ -2,22 +2,25 @@ import { ImageWithFallback } from '@components/imageWithFallback'; import { RelayContext } from '@components/relaysProvider'; import { activeAccountAtom } from '@stores/account'; +import { noteContentAtom } from '@stores/note'; import { relaysAtom } from '@stores/relays'; import { dateToUnix } from '@utils/getDate'; import destr from 'destr'; import { useAtom, useAtomValue } from 'jotai'; +import { useResetAtom } from 'jotai/utils'; import { getEventHash, signEvent } from 'nostr-tools'; -import { useContext, useState } from 'react'; +import { useContext } from 'react'; -export default function FormComment({ eventID }: { eventID: any }) { +export default function FormComment({ eventID }: { eventID: string }) { const pool: any = useContext(RelayContext); const relays = useAtomValue(relaysAtom); const [activeAccount] = useAtom(activeAccountAtom); + const [value, setValue] = useAtom(noteContentAtom); + const resetValue = useResetAtom(noteContentAtom); - const [value, setValue] = useState(''); const profile = destr(activeAccount.metadata); const submitEvent = () => { @@ -32,6 +35,7 @@ export default function FormComment({ eventID }: { eventID: any }) { event.sig = signEvent(event, activeAccount.privkey); pool.publish(event, relays); + resetValue; }; return ( diff --git a/src/components/form/emojiPicker.tsx b/src/components/form/emojiPicker.tsx new file mode 100644 index 00000000..7b57fa67 --- /dev/null +++ b/src/components/form/emojiPicker.tsx @@ -0,0 +1,37 @@ +import { noteContentAtom } from '@stores/note'; + +import EmojiIcon from '@assets/icons/emoji'; + +import data from '@emoji-mart/data'; +import Picker from '@emoji-mart/react'; +import * as Popover from '@radix-ui/react-popover'; +import { useAtom } from 'jotai'; + +export default function EmojiPicker() { + const [value, setValue] = useAtom(noteContentAtom); + + return ( + + + + + + + setValue(value + ' ' + res.native)} + /> + + + + + ); +} diff --git a/src/pages/newsfeed/[id].tsx b/src/pages/newsfeed/[id].tsx index d5229596..9c9540ba 100644 --- a/src/pages/newsfeed/[id].tsx +++ b/src/pages/newsfeed/[id].tsx @@ -1,8 +1,8 @@ import BaseLayout from '@layouts/base'; import WithSidebarLayout from '@layouts/withSidebar'; +import FormComment from '@components/form/comment'; import { NoteExtend } from '@components/note/extend'; -import FormComment from '@components/note/form/comment'; import { RelayContext } from '@components/relaysProvider'; import { relaysAtom } from '@stores/relays'; diff --git a/src/pages/newsfeed/following.tsx b/src/pages/newsfeed/following.tsx index b62b6736..f3cc9cc0 100644 --- a/src/pages/newsfeed/following.tsx +++ b/src/pages/newsfeed/following.tsx @@ -1,8 +1,8 @@ import BaseLayout from '@layouts/base'; import WithSidebarLayout from '@layouts/withSidebar'; +import FormBasic from '@components/form/base'; import { NoteBase } from '@components/note/base'; -import FormBasic from '@components/note/form/basic'; import { Placeholder } from '@components/note/placeholder'; import { notesAtom } from '@stores/note'; diff --git a/src/stores/note.tsx b/src/stores/note.tsx index 9d079aa2..443ebc38 100644 --- a/src/stores/note.tsx +++ b/src/stores/note.tsx @@ -3,7 +3,10 @@ import { getAllNotes } from '@utils/storage'; import { atom } from 'jotai'; import { atomsWithQuery } from 'jotai-tanstack-query'; +import { atomWithReset } from 'jotai/utils'; +// note content +export const noteContentAtom = atomWithReset(''); // notify user that connector has receive newer note export const hasNewerNoteAtom = atom(false); // query notes from database