Skip to content

Commit

Permalink
wip: note linking
Browse files Browse the repository at this point in the history
  • Loading branch information
cloverich committed Aug 26, 2024
1 parent cbb3641 commit a68fd69
Show file tree
Hide file tree
Showing 19 changed files with 1,076 additions and 51 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"test": "mocha 'src/**/*.test.bundle.js'"
},
"dependencies": {
"@ariakit/react": "^0.4.8",
"ajv": "^8.6.2",
"ajv-formats": "^2.1.0",
"better-sqlite3": "^9.2.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -364,14 +364,36 @@ function createBreak(node: mdast.Break) {

export type Link = ReturnType<typeof createLink>;

const noteLinkRegex = /^\.\/(?:(.+)\/)?([a-zA-Z0-9-]+)\.md$/;

function checkNoteLink(url: string) {
if (!url) return { noteId: null, journalName: null };

const match = url.match(noteLinkRegex);
const journalName = match ? match[1] : null;
const noteId = match ? match[2] : null;
return { noteId, journalName };
}

function createLink(node: mdast.Link, deco: Decoration) {
const { type, children, url, title } = node;
return {
type: "a", // NOTE: Default plate link component uses "a"
children: convertNodes(children, deco),
url,
title,
};
const res = checkNoteLink(url);

if (res.noteId) {
return {
type: "noteLinkElement",
children: convertNodes(children, deco),
title: "",
...res,
};
} else {
return {
type: "a", // NOTE: Default plate link component uses "a"
children: convertNodes(children, deco),
url,
title,
};
}
}

export type Image = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,8 @@ function createMdastNode(
return createImage(node);
case "linkReference":
return createLinkReference(node);
case "noteLinkElement":
return createNoteLinkReference(node);
case "imageReference":
return createImageReference(node);
case "footnote":
Expand Down Expand Up @@ -468,6 +470,26 @@ function createLink(node: SlateNodes.Link): mdast.Link {
} as any;
}

interface SlateNoteLink {
noteId: string; // ex: "019141a8-dc3e-7d8e-b74c-c05d654f3b5e"
type: "noteLinkElement";
title: string;
journalName: string;
children: any;
}

function createNoteLinkReference(node: SlateNoteLink): mdast.Link {
const { type, title, noteId, journalName, children } = node;
const url = `./${journalName}/${noteId}.md`;

return {
type: "link", // note: changes from type to type: "link" so it can accept "a", see the switch statement
url, // note: converted, "as any" added because mdast.Link thinks its url and not link?
title,
children: convertNodes(children) as any as mdast.Link["children"],
} as any;
}

function createImage(node: SlateNodes.Image | SlateNodes.Video): mdast.Image {
const { type, url, title, alt } = node;
return {
Expand Down
57 changes: 37 additions & 20 deletions src/views/edit/PlateContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from "react";
import React, { useContext } from "react";
import { withProps } from "@udecode/cn";
import { observer } from "mobx-react-lite";
import { Node as SNode } from "slate";
import { Editor, Node as SNode } from "slate";
import {
Plate,
PlateContent,
Expand All @@ -11,6 +11,7 @@ import {
createHistoryPlugin,
isBlockAboveEmpty,
isSelectionAtBlockStart,
isSelectionAtBlockEnd,
PlateLeaf,
PlateElement,
} from "@udecode/plate-common";
Expand Down Expand Up @@ -73,7 +74,6 @@ import {
createLinkPlugin,
createSoftBreakPlugin,
createExitBreakPlugin,
createResetNodePlugin,
createListPlugin,
} from "@udecode/plate";

Expand All @@ -96,6 +96,17 @@ import {

import { autoformatRules } from "./editor/plugins/autoformat/autoformatRules";
import { createCodeBlockNormalizationPlugin } from "./editor/plugins/createCodeBlockNormalizationPlugin";
import { createResetNodePlugin } from "./editor/plugins/createResetNodePlugin";
import { createInlineEscapePlugin } from "./editor/plugins/createInlineEscapePlugin";
import {
ELEMENT_MENTION,
ELEMENT_NOTE_LINK,
createNoteLinkDropdownPlugin,
NoteLinkDropdownElement,
NoteLinkElement,
} from "./editor/features/note-linking";

import { createNoteLinkElementPlugin } from "./editor/features/note-linking/createNoteLinkElementPlugin";

import {
ELEMENT_VIDEO,
Expand All @@ -121,8 +132,16 @@ export interface Props {
setSelectedEditorMode: (s: EditorMode) => any;
}

import { JournalsStoreContext } from "../../hooks/useJournalsLoader";
import useClient from "../../hooks/useClient";
import { SearchStore } from "../documents/SearchStore";

export default observer(
({ children, saving, value, setValue }: React.PropsWithChildren<Props>) => {
const jstore = useContext(JournalsStoreContext);
const client = useClient();
const store = new SearchStore(client, jstore!, () => {}, []);

const plugins = createPlugins(
[
createCodeBlockNormalizationPlugin(),
Expand Down Expand Up @@ -166,6 +185,8 @@ export default observer(
// dropped video files and this won't be called.
createVideoPlugin(),
createFilesPlugin(),
createNoteLinkDropdownPlugin({ options: { store } } as any),
createNoteLinkElementPlugin(),

// Backspacing into an element selects the block before deleting it.
createSelectOnBackspacePlugin({
Expand Down Expand Up @@ -256,6 +277,11 @@ export default observer(
},
}),

// When editing "inline" elements, allow space at the end to "escape" from the element.
// ex: link or note link editing.
// See plugin comments for links and details; this is
createInlineEscapePlugin(),

// Set text block indentation for differentiating structural
// elements or emphasizing certain content sections.
// https://platejs.org/docs/indent
Expand Down Expand Up @@ -286,7 +312,8 @@ export default observer(
// being confused about how to exit an e.g. code block to add more content.
createTrailingBlockPlugin({ type: ELEMENT_PARAGRAPH }),

// e.g. # -> h1, ``` -> code block, etc
// convert markdown to wysiwyg sa you type:
// # -> h1, ``` -> code block, etc
createAutoformatPlugin({
options: {
rules: autoformatRules,
Expand All @@ -302,7 +329,6 @@ export default observer(
[ELEMENT_CODE_LINE]: CodeLineElement,
[ELEMENT_CODE_SYNTAX]: CodeSyntaxLeaf,
[MARK_CODE]: CodeLeaf,
// [ELEMENT_HR]: HrElement,
[ELEMENT_H1]: withProps(HeadingElement, { variant: "h1" }),
[ELEMENT_H2]: withProps(HeadingElement, { variant: "h2" }),
[ELEMENT_H3]: withProps(HeadingElement, { variant: "h3" }),
Expand All @@ -311,31 +337,22 @@ export default observer(
[ELEMENT_H6]: withProps(HeadingElement, { variant: "h6" }),
[ELEMENT_IMAGE]: ImageElement,
[ELEMENT_LINK]: LinkElement,
// todo: need more plugins to make these truly usable.
// [ELEMENT_MEDIA_EMBED]: MediaEmbedElement,
// [ELEMENT_MENTION]: MentionElement,
// [ELEMENT_MENTION_INPUT]: MentionInputElement,

// NoteRefDropdown provides the dropdown when typing `@`; NoteLinkElement
// is the actual element that gets inserted when you select a note.
[ELEMENT_MENTION]: NoteLinkDropdownElement,
[ELEMENT_NOTE_LINK]: NoteLinkElement,

[ELEMENT_UL]: withProps(ListElement, { variant: "ul" }),
[ELEMENT_LI]: withProps(PlateElement, { as: "li" }),
[ELEMENT_OL]: withProps(ListElement, { variant: "ol" }),
[ELEMENT_PARAGRAPH]: ParagraphElement,
// [ELEMENT_TABLE]: TableElement,
// [ELEMENT_TD]: TableCellElement,
// [ELEMENT_TH]: TableCellHeaderElement,
// [ELEMENT_TODO_LI]: TodoListElement,
// [ELEMENT_TR]: TableRowElement,
// [ELEMENT_EXCALIDRAW]: ExcalidrawElement,
[MARK_BOLD]: withProps(PlateLeaf, { as: "strong" }),

// Unsure about these:
// [MARK_HIGHLIGHT]: HighlightLeaf,
[MARK_ITALIC]: withProps(PlateLeaf, { as: "em" }),
// [MARK_KBD]: KbdLeaf,
[MARK_STRIKETHROUGH]: withProps(PlateLeaf, { as: "s" }),
[MARK_SUBSCRIPT]: withProps(PlateLeaf, { as: "sub" }),
[MARK_SUPERSCRIPT]: withProps(PlateLeaf, { as: "sup" }),
[MARK_UNDERLINE]: withProps(PlateLeaf, { as: "u" }),
// [MARK_COMMENT]: CommentLeaf,
},
},
);
Expand Down
Loading

0 comments on commit a68fd69

Please sign in to comment.