Skip to content

Commit

Permalink
实现 *Markstep 保存
Browse files Browse the repository at this point in the history
paragraph 和 garagraph 初分离,可能存在某些 bug
  • Loading branch information
ljm12914 committed Feb 8, 2025
1 parent f378110 commit 127ee41
Show file tree
Hide file tree
Showing 28 changed files with 331 additions and 104 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "lotion",
"private": true,
"version": "0.3.0",
"version": "0.4.0",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down
1 change: 0 additions & 1 deletion src/components/App/App.module.css

This file was deleted.

23 changes: 21 additions & 2 deletions src/components/App/App.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,29 @@
import styles from "./App.module.css";
import Editor from "../Editor/Editor";
import Sidebar from "../Sidebar/Sidebar";
import Debug from "../Debug/Debug";
import { useEffect, useState } from "react";
import { configTable } from "../../data/db";
import { newDocument, UUID } from "../../data/block";
import { Table } from "dexie";
import { DcConfigEntry } from "../../data/config";
import meta from "../../data/meta";

export default function App(){
const
[cursorAnchor, setCursorAnchor] = useState(0),
[cursorFocus, setCursorFocus] = useState(0),
[docSize, setDocSize] = useState(0),
[documentId, setDocumentId] = useState<UUID>("" as UUID);
useEffect(()=>{(async ()=>{
const currentDocument = await (configTable as Table<DcConfigEntry<"currentDocument">, "currentDocument">).get("currentDocument");
if(!currentDocument || currentDocument.value === null) setDocumentId(await newDocument());
//检查文档是否是有效的。目前先不检查了
//else if()
else setDocumentId(currentDocument.value);
})()}, []);
return(<>
{meta.dev ? <Debug cursorAnchor={cursorAnchor} cursorFocus={cursorFocus} docSize={docSize} /> : null}
<Sidebar />
<Editor />
<Editor debug={{setCursorAnchor, setDocSize, setCursorFocus}} documentId={documentId} />
</>);
}
19 changes: 19 additions & 0 deletions src/components/Debug/Debug.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@

type Props = {
cursorAnchor :number;
cursorFocus :number;
docSize :number;
};

export default function Debug({cursorAnchor, cursorFocus, docSize} :Props){
return(<div style={{
position: "absolute",
fontSize: ".9rem",
top: "2rem",
left: "2rem",
zIndex: "6666666"
}}>
<div>pos: {cursorAnchor === cursorFocus ? cursorAnchor : `${cursorAnchor}-${cursorFocus}`}</div>
<div>size: {docSize}</div>
</div>);
}
59 changes: 43 additions & 16 deletions src/components/Editor/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@ import "./css/editor.css";
import "./css/editor.color.css";
import "./css/trailingbreak.css";

import { configTable } from "../../data/db";
import { getDocument, UUID } from "../../data/block";
import PopupMenu from "./PopupMenu";

import { useEffect } from "react";
import { Dispatch, SetStateAction, useCallback, useEffect, useRef } from "react";
import { EditorContent, useEditor } from "@tiptap/react";

import CodeBlockLowlight from "@tiptap/extension-code-block-lowlight";
Expand All @@ -32,8 +31,6 @@ import Heading from "@tiptap/extension-heading";
import Text from "@tiptap/extension-text";
import HardBreak from "@tiptap/extension-hard-break";

//import { Bold } from "@tiptap/extension-bold";
//import { Italic } from "@tiptap/extension-italic";
import Bold from "./extensions/mark/bold";
import Italic from "./extensions/mark/italic";
import Underline from "./extensions/mark/underline";
Expand All @@ -45,14 +42,27 @@ import Highlight from "@tiptap/extension-highlight";
import Superscript from "@tiptap/extension-superscript";
import Subscript from "@tiptap/extension-subscript";
import BubbleMenu from "@tiptap/extension-bubble-menu";
import AppendParagraph from "./extensions/technical/appendParagraph";
import NoSelectTB from "./extensions/technical/noSelectTB";
import Garagraph from "./extensions/block/garagraph";

type Props = {
documentId :UUID;
debug :{
setCursorAnchor :Dispatch<SetStateAction<number>>;
setDocSize :Dispatch<SetStateAction<number>>;
setCursorFocus :Dispatch<SetStateAction<number>>;
}
};

const lowlight = createLowlight(all);

export default function Editor(){
const editor = useEditor({
export default function Editor({documentId, debug} :Props){
const
editor = useEditor({
extensions: [
//技术性扩展
History, BlockID, NoUndoSetIniContent, ClearMarks,
History, BlockID, NoUndoSetIniContent, ClearMarks, AppendParagraph, NoSelectTB,
BubbleMenu.configure({
updateDelay: 250,
tippyOptions: {
Expand All @@ -71,7 +81,10 @@ export default function Editor(){
placeholder: ""
}),
//块级节点
Document, Paragraph, Blockquote, BulletList, OrderedList, Heading.configure({levels: [1, 2, 3, 4]}),
//Document没有渲染结果,是一个虚拟块,没必要自己开发
//Garagraph是能够内嵌其他段落的paragraph
Document, Paragraph, Garagraph, Blockquote, BulletList, OrderedList, Heading.configure({levels: [1, 2, 3, 4]}),
CodeBlockLowlight.configure({lowlight}),
//行内节点
Text, HardBreak,
//标记节点
Expand All @@ -84,25 +97,39 @@ export default function Editor(){
}),
//未处理
Highlight, Superscript, Subscript,
CodeBlockLowlight.configure({lowlight}),
HorizontalRule,
Image,
//这是一个基底扩展,用来做文字颜色
TextStyle,
],
injectCSS: false,
//这里仅供debug使用
//其他逻辑请使用插件添加
onSelectionUpdate(props){
debug.setCursorAnchor(props.editor.state.selection.anchor);
debug.setCursorFocus(props.editor.state.selection.head);
},
onUpdate(props){
console.log(props);
//不是props.editor.state.doc.nodeSize!https://prosemirror.net/docs/guide/#doc:~:text=Note%20that%20for%20the%20outer%20document%20node%2C%20the%20open%20and%20close%20tokens%20are%20not%20considered%20part%20of%20the%20document%20(because%20you%20can%27t%20put%20your%20cursor%20outside%20of%20the%20document)%2C%20so%20the%20size%20of%20a%20document%20is%20doc.content.size%2C%20not%20doc.nodeSize.
debug.setDocSize(props.editor.state.doc.content.size);
}
});
}),
editorOuter = useRef<HTMLDivElement>(null),
clickCB = useCallback((event :React.MouseEvent<HTMLDivElement>)=>{
//console.log(editor!.state.selection.$anchor);
if(
event.target === editorOuter.current?.childNodes[0]
&& editor!.state.selection.$anchor.parent.content.size !== 0
&& editor!.state.selection.empty
) editor!.commands.appendParagraph();
}, []);
useEffect(()=>{(async ()=>{
const
currentDocumentA = await configTable.get("currentDocument"),
iniContent = await getDocument(currentDocumentA ? currentDocumentA.value as UUID | null : currentDocumentA);
const iniContent = await getDocument(documentId);
//console.log(iniContent);
editor!.commands.setIniContent(iniContent);
})()}, []);
})()}, [documentId]);
return(<>
<EditorContent editor={editor} className={`${styles.outer} dc-container-outer`} />
<EditorContent editor={editor} className={`${styles.outer} dc-container-outer`} ref={editorOuter} onClick={clickCB} />
{editor ? <PopupMenu editor={editor} /> : null}
</>);
}
3 changes: 1 addition & 2 deletions src/components/Editor/PopupMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
import styles from "./PopupMenu.module.css";
import gStyles from "../../css/main.module.css";
import { BubbleMenu, Editor } from "@tiptap/react";
import { autoUpdate, flip, offset, shift, useFloating, useFocus, useHover, useInteractions } from "@floating-ui/react";
import { forwardRef, useCallback, useState } from "react";
import { useCallback } from "react";
import { Tooltip, TooltipContent, TooltipTrigger } from "../Tooltip/Tooltip";

interface EditorProps{
Expand Down
8 changes: 5 additions & 3 deletions src/components/Editor/css/editor.css
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
:root{
--dc-p-padding-inline: .15rem;
--dc-p-padding-block: .225rem;
--dc-p-padding-block: .28125rem;
--dc-p-padding-inline: .1875rem;
}

.tiptap{
box-sizing: border-box;
width: 100%;
min-height: 100vh;
min-height: 100dvh;
padding: 3rem 4rem 40vh;
padding: 3rem 4rem 40dvh;
}
Expand Down Expand Up @@ -40,7 +42,7 @@
.dc-p{
padding: var(--dc-p-padding-block) var(--dc-p-padding-inline);
background-color: aliceblue;
border-radius: .15rem;
border-radius: .1875rem;
}

.dc-ul{
Expand Down
2 changes: 1 addition & 1 deletion src/components/Editor/extensions/block/blockquote.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { NodeViewContent, NodeViewWrapper, ReactNodeViewRenderer } from "@tiptap
const Blockquote = Node.create({
name: "blockquote",
content: "paragraph block*",
group: "block",
group: "block groupable",
draggable: true,
parseHTML: ()=>[
{tag: "div.dc-bq"},
Expand Down
2 changes: 1 addition & 1 deletion src/components/Editor/extensions/block/bulletList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const BulletList = Node.create({
//https://github.com/ueberdosis/tiptap/blob/b7a7b2ad85cce18449bf856fac8a8b6a301f502c/packages/core/src/inputRules/wrappingInputRule.ts#L68
name: "bulletlist",
content: "paragraph block*",
group: "block",
group: "block dclist groupable",
defining: true,
draggable: true,
parseHTML: ()=>[
Expand Down
26 changes: 26 additions & 0 deletions src/components/Editor/extensions/block/garagraph.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { mergeAttributes, Node } from "@tiptap/core";

declare module "@tiptap/core"{
interface Commands<ReturnType>{
garagraph :{
setGaragraph :()=>ReturnType;
}
}
}

const Garagraph = Node.create({
name: "garagraph",
content: "paragraph block*",
group: "block groupable",
draggable: true,
parseHTML: ()=>[
{tag: "div.dc-gp"},
{tag: "div:has(div.dc-p)"}
],
renderHTML: ({HTMLAttributes})=>["div", mergeAttributes(HTMLAttributes, {class: "dc-gp"}), 0],
addCommands(){return{
setGaragraph: ()=>({commands})=>commands.setNode(this.name),
}},
});

export default Garagraph;
2 changes: 1 addition & 1 deletion src/components/Editor/extensions/block/orderedList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const OrderedList = Node.create({
//https://github.com/ueberdosis/tiptap/blob/b7a7b2ad85cce18449bf856fac8a8b6a301f502c/packages/core/src/inputRules/wrappingInputRule.ts#L68
name: "orderedlist",
content: "paragraph block*",
group: "block",
group: "block dclist groupable",
defining: true,
draggable: true,
parseHTML: ()=>[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const Paragraph = _Paragraph.extend({
{tag: "div"},
{tag: "p"}
],
renderHTML: ({HTMLAttributes, node})=>["div", mergeAttributes(HTMLAttributes, {class: "dc-p"}), 0]
renderHTML: ({HTMLAttributes})=>["div", mergeAttributes(HTMLAttributes, {class: "dc-p"}), 0]
});

export default Paragraph;
2 changes: 1 addition & 1 deletion src/components/Editor/extensions/inline/formula.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

declare module "@tiptap/core"{
interface Commands<ReturnType>{
formulaInline: {
formulaInline :{
setFormulaInline: ()=>ReturnType;
unsetFormulaInline: ()=>ReturnType;
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/Editor/extensions/mark/bold.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Mark, markInputRule, markPasteRule } from "@tiptap/core";

declare module "@tiptap/core"{
interface Commands<ReturnType>{
bold: {
bold :{
setBold :()=>ReturnType;
toggleBold :()=>ReturnType;
unsetBold :()=>ReturnType;
Expand Down
2 changes: 1 addition & 1 deletion src/components/Editor/extensions/mark/code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Mark, markInputRule, markPasteRule } from "@tiptap/core";

declare module "@tiptap/core"{
interface Commands<ReturnType>{
code: {
code :{
setCode: ()=>ReturnType;
toggleCode: ()=>ReturnType;
unsetCode: ()=>ReturnType;
Expand Down
2 changes: 1 addition & 1 deletion src/components/Editor/extensions/mark/italic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Mark, markInputRule, markPasteRule } from "@tiptap/core";

declare module "@tiptap/core"{
interface Commands<ReturnType>{
italic: {
italic :{
setItalic: ()=>ReturnType;
toggleItalic: ()=>ReturnType;
unsetItalic: ()=>ReturnType;
Expand Down
2 changes: 1 addition & 1 deletion src/components/Editor/extensions/mark/strike.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Mark, markInputRule, markPasteRule } from "@tiptap/core";

declare module "@tiptap/core"{
interface Commands<ReturnType>{
strike: {
strike :{
setStrike: ()=>ReturnType;
toggleStrike: ()=>ReturnType;
unsetStrike: ()=>ReturnType;
Expand Down
2 changes: 1 addition & 1 deletion src/components/Editor/extensions/mark/underline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Mark, markInputRule, markPasteRule } from "@tiptap/core";

declare module "@tiptap/core"{
interface Commands<ReturnType>{
underline: {
underline :{
setUnderline: ()=>ReturnType;
toggleUnderline: ()=>ReturnType;
unsetUnderline: ()=>ReturnType;
Expand Down
22 changes: 22 additions & 0 deletions src/components/Editor/extensions/technical/appendParagraph.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Extension } from "@tiptap/react";

declare module "@tiptap/core"{
interface Commands<ReturnType>{
appendParagraph :{
appendParagraph :()=>ReturnType;
}
}
}

const AppendParagraph = Extension.create({
name: "appendParagraph",
addCommands(){return{
appendParagraph: ()=>({dispatch, tr, state, commands})=>{
if(!dispatch) return true;
commands.insertContentAt(state.doc.content.size, {type: "paragraph"});
return true;
}
}}
});

export default AppendParagraph;
Loading

0 comments on commit 127ee41

Please sign in to comment.