From d2f6b1b4c754225b65244bb6089415c9c4274bae Mon Sep 17 00:00:00 2001 From: Tom Sherman Date: Fri, 19 Jul 2024 23:56:32 +0100 Subject: [PATCH] WIP --- .../[postAuthor]/[postRkey]/_lib/actions.tsx | 62 +++- .../[postRkey]/_lib/comment-client.tsx | 39 +- .../frontpage/lib/components/ui/textarea.tsx | 303 ++++++++++++++- .../lib/components/ui/toggle-group.tsx | 61 +++ .../frontpage/lib/components/ui/toggle.tsx | 45 +++ packages/frontpage/package.json | 9 + pnpm-lock.yaml | 346 ++++++++++++++++++ 7 files changed, 819 insertions(+), 46 deletions(-) create mode 100644 packages/frontpage/lib/components/ui/toggle-group.tsx create mode 100644 packages/frontpage/lib/components/ui/toggle.tsx diff --git a/packages/frontpage/app/(app)/post/[postAuthor]/[postRkey]/_lib/actions.tsx b/packages/frontpage/app/(app)/post/[postAuthor]/[postRkey]/_lib/actions.tsx index 6e6b3137..a4d67b0e 100644 --- a/packages/frontpage/app/(app)/post/[postAuthor]/[postRkey]/_lib/actions.tsx +++ b/packages/frontpage/app/(app)/post/[postAuthor]/[postRkey]/_lib/actions.tsx @@ -13,14 +13,26 @@ import { parseReportForm } from "@/lib/data/db/report-shared"; import { createReport } from "@/lib/data/db/report"; import { getVoteForComment } from "@/lib/data/db/vote"; import { ensureUser } from "@/lib/data/user"; +import { createHeadlessEditor } from "@lexical/headless"; +import { + SerializedEditorState, + $parseSerializedNode, + LexicalEditor, + $getRoot, + EditorState, + LexicalNode, + $isTextNode, + $isElementNode, +} from "lexical"; import { revalidatePath } from "next/cache"; +import { deletePost } from "@/lib/data/atproto/post"; -export async function createCommentAction( - input: { parentRkey?: string; postRkey: string; postAuthorDid: DID }, - _prevState: unknown, - formData: FormData, -) { - const content = formData.get("comment") as string; +export async function createCommentAction(input: { + parentRkey?: string; + postRkey: string; + postAuthorDid: DID; + content: SerializedEditorState; +}) { const user = await ensureUser(); const [post, comment] = await Promise.all([ @@ -41,13 +53,15 @@ export async function createCommentAction( throw new Error(`[naughty] Cannot comment on deleted post. ${user.did}`); } - const { rkey } = await createComment({ - content, - post, - parent: comment, - }); - await waitForComment(rkey); - revalidatePath(`/post`); + const state = createHeadlessEditor().parseEditorState(input.content); + + // const { rkey } = await createComment({ + // content, + // post, + // parent: comment, + // }); + // await waitForComment(rkey); + // revalidatePath(`/post`); } const MAX_POLLS = 15; @@ -64,6 +78,28 @@ async function waitForComment(rkey: string) { } } +function editorStateToCommentContent(editorState: EditorState) { + return editorState.read(() => { + const root = $getRoot(); + root.getChildren().forEach((child) => {}); + + const text = root.getTextContent(); + }); +} + +function $nodeToFacets(node: LexicalNode) { + if ($isTextNode(node)) { + if (node.hasFormat("bold")) { + return node.selectStart; + } + } + if ($isElementNode(node) && node.isEmpty()) return []; +} + +export async function deletePostAction(rkey: string) { + await deletePost(rkey); +} + export async function deleteCommentAction(rkey: string) { await ensureUser(); await deleteComment(rkey); diff --git a/packages/frontpage/app/(app)/post/[postAuthor]/[postRkey]/_lib/comment-client.tsx b/packages/frontpage/app/(app)/post/[postAuthor]/[postRkey]/_lib/comment-client.tsx index e8fd4cac..0afc8071 100644 --- a/packages/frontpage/app/(app)/post/[postAuthor]/[postRkey]/_lib/comment-client.tsx +++ b/packages/frontpage/app/(app)/post/[postAuthor]/[postRkey]/_lib/comment-client.tsx @@ -11,7 +11,7 @@ import { AlertDialogTrigger, } from "@/lib/components/ui/alert-dialog"; import { Button } from "@/lib/components/ui/button"; -import { Textarea } from "@/lib/components/ui/textarea"; +import { EditableTextArea } from "@/lib/components/ui/textarea"; import { SimpleTooltip } from "@/lib/components/ui/tooltip"; import { useToast } from "@/lib/components/ui/use-toast"; import { @@ -22,13 +22,7 @@ import { reportCommentAction, } from "./actions"; import { ChatBubbleIcon, TrashIcon } from "@radix-ui/react-icons"; -import { - useActionState, - useRef, - useState, - useId, - startTransition, -} from "react"; +import { useRef, useState, useId, startTransition, useTransition } from "react"; import { VoteButton, VoteButtonState, @@ -44,6 +38,7 @@ import { DeleteButton } from "@/app/(app)/_components/delete-button"; import { cva, VariantProps } from "class-variance-authority"; import { cn } from "@/lib/utils"; import { ShareDropdownButton } from "@/app/(app)/_components/share-button"; +import { LexicalEditor } from "lexical"; const commentVariants = cva(undefined, { variants: { @@ -226,7 +221,6 @@ export function NewComment({ postRkey, postAuthorDid, extraButton, - textAreaRef, onActionDone, }: { parentRkey?: string; @@ -237,23 +231,28 @@ export function NewComment({ extraButton?: React.ReactNode; textAreaRef?: React.RefObject; }) { + const editorRef = useRef(null); const [input, setInput] = useState(""); - const [_, action, isPending] = useActionState( - createCommentAction.bind(null, { parentRkey, postRkey, postAuthorDid }), - undefined, - ); + const [isPending, startTransition] = useTransition(); + const id = useId(); const textAreaId = `${id}-comment`; return (
{ event.preventDefault(); - startTransition(() => { - action(new FormData(event.currentTarget)); + startTransition(async () => { + const state = editorRef.current?.getEditorState().toJSON(); + if (!state) throw new Error("Empty comment"); + console.log(state); + await createCommentAction({ + parentRkey, + postRkey, + postAuthorDid, + content: state, + }); onActionDone?.(); - setInput(""); }); }} aria-busy={isPending} @@ -271,7 +270,7 @@ export function NewComment({ }} className="space-y-2" > -