"use client" import * as React from "react" import { useAtom } from "jotai" import { ID } from "jazz-tools" import { PersonalPage, Topic } from "@/lib/schema" import { useCallback, useRef, useEffect, useState } from "react" import { LAEditor, LAEditorRef } from "@/components/la-editor" import { Content, EditorContent, useEditor } from "@tiptap/react" import { StarterKit } from "@/components/la-editor/extensions/starter-kit" import { Paragraph } from "@/components/la-editor/extensions/paragraph" import { useAccount, useCoState } from "@/lib/providers/jazz-provider" import { EditorView } from "@tiptap/pm/view" import { Editor } from "@tiptap/core" import { generateUniqueSlug } from "@/lib/utils" import { Button } from "@/components/ui/button" import { LaIcon } from "@/components/custom/la-icon" import { pageTopicSelectorAtom } from "@/store/page" import { TopicSelector } from "@/components/routes/link/partials/form/topic-selector" import { FocusClasses } from "@tiptap/extension-focus" import DeletePageModal from "@/components/custom/delete-modal" const TITLE_PLACEHOLDER = "Untitled" export function PageDetailRoute({ pageId }: { pageId: string }) { const page = useCoState(PersonalPage, pageId as ID) if (!page) return
Loading...
return (
) } export const DetailPageForm = ({ page }: { page: PersonalPage }) => { const { me } = useAccount() const titleEditorRef = useRef(null) const contentEditorRef = useRef(null) const [, setTopicSelectorOpen] = useAtom(pageTopicSelectorAtom) const [, setSelectedPageTopic] = useState(page.topic || null) const [deleteModalOpen, setDeleteModalOpen] = useState(false) const isTitleInitialMount = useRef(true) const isContentInitialMount = useRef(true) const updatePageContent = (content: Content, model: PersonalPage) => { if (isContentInitialMount.current) { isContentInitialMount.current = false return } console.log("Updating page content") model.content = content model.updatedAt = new Date() } const handleUpdateTitle = (editor: Editor) => { if (isTitleInitialMount.current) { isTitleInitialMount.current = false return } /* * The logic changed, but we keep this commented code for reference */ // const newTitle = editor.getText().trim() // if (!newTitle) { // toast.error("Update failed", { // description: "Title must be longer than or equal to 1 character" // }) // editor.commands.setContent(page.title || "") // return // } // if (newTitle === page.title) return console.log("Updating page title") const personalPages = me.root?.personalPages?.toJSON() || [] const slug = generateUniqueSlug(personalPages, page.slug || "") const trimmedTitle = editor.getText().trim() page.title = trimmedTitle page.slug = slug page.updatedAt = new Date() editor.commands.setContent(trimmedTitle) } const handleTitleKeyDown = useCallback((view: EditorView, event: KeyboardEvent) => { const editor = titleEditorRef.current if (!editor) return false const { state } = editor const { selection } = state const { $anchor } = selection if ((event.key === "ArrowLeft" || event.key === "ArrowUp") && $anchor.pos - 1 === 0) { event.preventDefault() titleEditorRef.current?.commands.focus("end") return true } return false }, []) const handleContentKeyDown = useCallback((view: EditorView, event: KeyboardEvent) => { const editor = contentEditorRef.current?.editor if (!editor) return false const { state } = editor const { selection } = state const { $anchor } = selection return false }, []) const confirmDelete = (page: PersonalPage) => { console.log("Deleting page:", page.id) setDeleteModalOpen(false) //TODO: add delete logic } const titleEditor = useEditor({ immediatelyRender: false, autofocus: true, extensions: [ FocusClasses, Paragraph, StarterKit.configure({ bold: false, italic: false, typography: false, hardBreak: false, listItem: false, strike: false, focus: false, gapcursor: false, history: false, placeholder: { placeholder: TITLE_PLACEHOLDER } }) ], editorProps: { attributes: { spellcheck: "true", role: "textbox", "aria-readonly": "false", "aria-multiline": "false", "aria-label": TITLE_PLACEHOLDER, translate: "no" }, handleKeyDown: handleTitleKeyDown }, onCreate: ({ editor }) => { if (page.title) editor.commands.setContent(`

${page.title}

`) }, onBlur: ({ editor }) => handleUpdateTitle(editor), onUpdate: ({ editor }) => { handleUpdateTitle(editor) } }) useEffect(() => { if (titleEditor) { titleEditorRef.current = titleEditor } }, [titleEditor]) useEffect(() => { isTitleInitialMount.current = true isContentInitialMount.current = true }, []) return (
{ page.topic = topic setSelectedPageTopic(topic) setTopicSelectorOpen(false) }} />
updatePageContent(c, page)} handleKeyDown={handleContentKeyDown} onBlur={c => updatePageContent(c, page)} onNewBlock={c => updatePageContent(c, page)} />
setDeleteModalOpen(false)} onConfirm={() => { confirmDelete(page) }} title={page.title || ""} />
) }