Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
Ignore errors while prototyping

WIP

WIP

Simple formatting

WIP
  • Loading branch information
tom-sherman committed Sep 26, 2024
1 parent e88fc19 commit bdd9843
Show file tree
Hide file tree
Showing 11 changed files with 1,062 additions and 48 deletions.
9 changes: 8 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
},
"args": [],
"cwd": "${workspaceFolder}/packages-rs/drainpipe",
"envFile": "${workspaceFolder}/packages-rs/drainpipe/.env"
"envFile": "${workspaceFolder}/packages-rs/drainpipe/.env"
},
{
"type": "lldb",
Expand All @@ -30,6 +30,13 @@
},
"args": [],
"cwd": "${workspaceFolder}"
},
{
"name": "Frontpage: debug full stack",
"type": "node-terminal",
"request": "launch",
"cwd": "${workspaceFolder}",
"command": "pnpm --filter=frontpage run dev"
}
]
}
Original file line number Diff line number Diff line change
@@ -1,27 +1,24 @@
"use server";

import {
CommentCollection,
createComment,
deleteComment,
} from "@/lib/data/atproto/comment";
import { CommentCollection, deleteComment } from "@/lib/data/atproto/comment";
import { DID } from "@/lib/data/atproto/did";
import { deletePost } from "@/lib/data/atproto/post";
import { createVote, deleteVote } from "@/lib/data/atproto/vote";
import { getComment, uncached_doesCommentExist } from "@/lib/data/db/comment";
import { getPost } from "@/lib/data/db/post";
import { getVoteForComment } from "@/lib/data/db/vote";
import { ensureUser } from "@/lib/data/user";
import { revalidatePath } from "next/cache";
import { createHeadlessEditor } from "@lexical/headless";
import { SerializedEditorState, RootNode } from "lexical";
import { editorStateToCommentContent } from "./editor-state-to-comment-content";

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();
console.log(input);

const [post, comment] = await Promise.all([

Check failure on line 23 in packages/frontpage/app/(app)/post/[postAuthor]/[postRkey]/_lib/actions.tsx

View workflow job for this annotation

GitHub Actions / lint

'comment' is assigned a value but never used. Allowed unused elements of array destructuring patterns must match /^_/u
getPost(input.postAuthorDid, input.postRkey),
Expand All @@ -41,13 +38,16 @@ 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);
editorStateToCommentContent(state);

// const { rkey } = await createComment({
// content,
// post,
// parent: comment,
// });
// await waitForComment(rkey);
// revalidatePath(`/post`);
}

const MAX_POLLS = 15;
Expand Down Expand Up @@ -97,3 +97,6 @@ export async function commentUnvoteAction(commentId: number) {

await deleteVote(vote.rkey);
}
function $getDepth(node: RootNode) {

Check failure on line 100 in packages/frontpage/app/(app)/post/[postAuthor]/[postRkey]/_lib/actions.tsx

View workflow job for this annotation

GitHub Actions / lint

'$getDepth' is defined but never used. Allowed unused vars must match /^_/u

Check failure on line 100 in packages/frontpage/app/(app)/post/[postAuthor]/[postRkey]/_lib/actions.tsx

View workflow job for this annotation

GitHub Actions / lint

'node' is defined but never used. Allowed unused args must match /^_/u
throw new Error("Function not implemented.");
}
Original file line number Diff line number Diff line change
Expand Up @@ -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, Textarea } from "@/lib/components/ui/textarea";

Check failure on line 14 in packages/frontpage/app/(app)/post/[postAuthor]/[postRkey]/_lib/comment-client.tsx

View workflow job for this annotation

GitHub Actions / lint

'Textarea' is defined but never used. Allowed unused vars must match /^_/u
import { SimpleTooltip } from "@/lib/components/ui/tooltip";
import { useToast } from "@/lib/components/ui/use-toast";
import {
Expand All @@ -27,6 +27,7 @@ import {
useState,
useId,
startTransition,
useTransition,
} from "react";
import {
VoteButton,
Expand All @@ -37,6 +38,7 @@ import { DID } from "@/lib/data/atproto/did";
import { InputLengthIndicator } from "@/lib/components/input-length-indicator";
import { MAX_COMMENT_LENGTH } from "@/lib/data/db/constants";
import type { CommentModel } from "@/lib/data/db/comment";
import { LexicalEditor } from "lexical";

export type CommentClientProps = Pick<
CommentModel,
Expand Down Expand Up @@ -224,7 +226,6 @@ export function NewComment({
postRkey,
postAuthorDid,
extraButton,
textAreaRef,
onActionDone,
}: {
parentRkey?: string;
Expand All @@ -235,23 +236,28 @@ export function NewComment({
extraButton?: React.ReactNode;
textAreaRef?: React.RefObject<HTMLTextAreaElement>;
}) {
const editorRef = useRef<LexicalEditor | null>(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 (
<form
action={action}
onSubmit={(event) => {
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}
Expand All @@ -269,7 +275,7 @@ export function NewComment({
}}
>
<div className="flex items-end gap-2">
<Textarea
<EditableTextArea
value={input}
onChange={(event) => {
setInput(event.target.value);
Expand All @@ -278,10 +284,10 @@ export function NewComment({
// eslint-disable-next-line jsx-a11y/no-autofocus
autoFocus={autoFocus}
name="comment"
ref={textAreaRef}
ref={editorRef}
placeholder="Write a comment..."
disabled={isPending}
className="resize-y flex-1"
className="resize-y flex-1 overflow-auto grow"
/>
<Button
className="flex flex-row gap-2"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import { createHeadlessEditor } from "@lexical/headless";
import {
$createParagraphNode,
$createTextNode,
$getRoot,
LexicalEditor,
} from "lexical";
import { beforeEach, expect, test } from "vitest";
import { editorStateToCommentContent } from "./editor-state-to-comment-content";
import { $createLinkNode, LinkNode } from "@lexical/link";
import { generateContent } from "@lexical/devtools-core";

let editor: LexicalEditor;
beforeEach(() => {
editor = createHeadlessEditor({
nodes: [LinkNode],
namespace: "",
onError: (error) => {
throw error;
},
});
});

async function update(updateFn: () => void) {
editor.update(updateFn);
await Promise.resolve();
}

function debugEditorState() {

Check failure on line 29 in packages/frontpage/app/(app)/post/[postAuthor]/[postRkey]/_lib/editor-state-to-comment-content.test.ts

View workflow job for this annotation

GitHub Actions / lint

'debugEditorState' is defined but never used. Allowed unused vars must match /^_/u
console.log(generateContent(editor, [], false));
}

test.only("simple string", async () => {
await update(() => {
$getRoot().append(
$createParagraphNode().append($createTextNode("Hello, world!")),
);
});

expect(editorStateToCommentContent(editor.getEditorState())).toEqual([
"Hello, world!",
]);
});

test("empty state", () => {
expect(editorStateToCommentContent(editor.getEditorState())).toEqual([]);
});

test("bold", async () => {
await update(() => {
$getRoot().append(
$createParagraphNode().append(
$createTextNode("Hello, "),
$createTextNode("world").toggleFormat("bold"),
$createTextNode("!"),
),
);
});

expect(editorStateToCommentContent(editor.getEditorState())).toEqual([
[
"Hello, ",
{
content: "world",
facets: [
{ $type: "fyi.frontpage.richtext.facet#format", format: "bold" },
],
},
"!",
],
]);
});

test("bold and italic", async () => {
await update(() => {
$getRoot().append(
$createParagraphNode().append(
$createTextNode("Hello, "),
$createTextNode("world").toggleFormat("bold").toggleFormat("italic"),
$createTextNode("!"),
),
);
});

expect(editorStateToCommentContent(editor.getEditorState())).toEqual([
[
"Hello, ",
{
content: "world",
facets: [
{ $type: "fyi.frontpage.richtext.facet#format", format: "bold" },
{ $type: "fyi.frontpage.richtext.facet#format", format: "italic" },
],
},
"!",
],
]);
});

test("link", async () => {
await update(() => {
$getRoot().append(
$createParagraphNode().append(
$createTextNode("Hello, "),
$createLinkNode("https://example.com").append(
$createTextNode("w"),
$createTextNode("or").toggleFormat("bold"),
$createTextNode("ld").toggleFormat("italic"),
),
),
);
});

expect(editorStateToCommentContent(editor.getEditorState())).toEqual([
"Hello, ",
{
content: [
"w",
{
content: "or",
facets: [
{ $type: "fyi.frontpage.richtext.facet#format", format: "bold" },
],
},
{
content: "ld",
facets: [
{ $type: "fyi.frontpage.richtext.facet#format", format: "italic" },
],
},
],
facets: [
{
$type: "fyi.frontpage.richtext.facet#link",
uri: "https://example.com",
},
],
},
"!",
]);
});

test("empty nodes are removed", async () => {
await update(() => {
$getRoot().append(
$createParagraphNode().append($createTextNode("A"), $createTextNode("")),
$createParagraphNode(),
$createParagraphNode().append($createLinkNode("https://example.com")),
);
});

expect(editorStateToCommentContent(editor.getEditorState())).toEqual(["A"]);
});
Loading

0 comments on commit bdd9843

Please sign in to comment.