Skip to content

Commit

Permalink
editor takes string and uses json
Browse files Browse the repository at this point in the history
  • Loading branch information
shawnmclean committed Dec 26, 2024
1 parent 85b3681 commit 68a1396
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,7 @@ export async function newNoteAction(
};
}

console.log(result.data);

throw new Error("Not implemented");
}
29 changes: 24 additions & 5 deletions apps/sovoli.com/src/app/(dashboard)/new/components/NoteForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,29 @@ export const NoteForm = () => {
newNoteAction,
null,
);
const json = `{
"type": "doc",
"content": [
{
"type": "paragraph",
"content": [
{
"type": "text",
"text": "Example "
},
{
"type": "text",
"marks": [
{
"type": "bold"
}
],
"text": "Text"
}
]
}
]
}`;

return (
<Form className="w-full" action={formAction}>
Expand All @@ -35,11 +58,7 @@ export const NoteForm = () => {
fullWidth
variant="bordered"
/>
<Editor
onUpdate={({ editor }) => {
console.log(editor.getJSON());
}}
/>
<Editor name="content" value={json} />
<div className="flex w-full justify-between gap-2">
<div className="w-full">
{state?.status === "error" && (
Expand Down
48 changes: 30 additions & 18 deletions apps/sovoli.com/src/components/Editor/Editor.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,53 @@
"use client";

import type { EditorOptions } from "@tiptap/react";
import { ButtonGroup } from "@sovoli/ui/components/button";
import type { EditorOptions, JSONContent } from "@tiptap/react";
import { useMemo, useState } from "react";
import { EditorContent, useEditor } from "@tiptap/react";
import StarterKit from "@tiptap/starter-kit";

import { MenuButtonRedo } from "./controls/MenuButtonRedo";
import { MenuButtonUndo } from "./controls/MenuButtonUndo";
import { MenuSelectHeading } from "./controls/MenuSelectHeading";
import { EditorMenu } from "./controls/EditorMenu";

// eslint-disable-next-line @typescript-eslint/no-empty-object-type
export interface EditorProps extends Partial<EditorOptions> {}
export interface EditorProps extends Partial<EditorOptions> {
name: string;
value?: string;
}

export const Editor = ({ name, value, ...rest }: EditorProps) => {
const jsonContent = useMemo(() => {
try {
return value
? (JSON.parse(value) as JSONContent)
: { type: "doc", content: [] };
} catch (error) {
console.error("Invalid JSON content provided to the editor:", error);
return { type: "doc", content: [] };
}
}, [value]);

const [editorValue, setEditorValue] = useState(JSON.stringify(jsonContent));

export const Editor = (props: EditorProps) => {
const editor = useEditor({
immediatelyRender: true,
extensions: [StarterKit],
editorProps: {
attributes: {
class:
"w-full max-w-full py-6 px-8 prose prose-base prose-blue prose-headings:scroll-mt-[80px] focus:outline-none",
},
},
...props,
content: jsonContent,
...rest,
onUpdate: ({ editor }) => {
// TODO: performance issues may arise here, use debounce later
setEditorValue(JSON.stringify(editor.getJSON()));
},
});

if (!editor) return null;

return (
<div className="w-full flex-row items-center gap-3 rounded-large border-2 border-default-200 shadow-sm focus-within:border-default-foreground hover:border-default-400 hover:focus-within:border-default-foreground">
<div className="flex flex-wrap gap-1 border-b-1 border-default-100 p-1">
<ButtonGroup variant="light">
<MenuButtonUndo editor={editor} />
<MenuButtonRedo editor={editor} />
</ButtonGroup>
<MenuSelectHeading editor={editor} />
</div>
<EditorMenu editor={editor} />
<EditorContent editor={editor} />
<input type="hidden" name={name} value={editorValue} />
</div>
);
};
22 changes: 22 additions & 0 deletions apps/sovoli.com/src/components/Editor/controls/EditorMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { Editor } from "@tiptap/core";
import { ButtonGroup } from "@sovoli/ui/components/button";

import { MenuButtonRedo } from "./MenuButtonRedo";
import { MenuButtonUndo } from "./MenuButtonUndo";
import { MenuSelectHeading } from "./MenuSelectHeading";

export interface EditorMenuProps {
editor: Editor;
}

export const EditorMenu = ({ editor }: EditorMenuProps) => {
return (
<div className="flex flex-wrap gap-1 border-b-1 border-default-100 p-1">
<ButtonGroup variant="light">
<MenuButtonUndo editor={editor} />
<MenuButtonRedo editor={editor} />
</ButtonGroup>
<MenuSelectHeading editor={editor} />
</div>
);
};
18 changes: 18 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 0 additions & 5 deletions pnpm-workspace.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,6 @@ packages:
- apps/*

catalog:
"@tanstack/react-query": 5.51.21
"@ts-rest/core": 3.51.0
"@ts-rest/open-api": 3.51.0
"@ts-rest/react-query": 3.51.0
"@ts-rest/serverless": 3.51.0
react: 19.0.0
react-dom: 19.0.0
lucide-react: 0.468.0
Expand Down

0 comments on commit 68a1396

Please sign in to comment.