aboutsummaryrefslogtreecommitdiff
path: root/apps/web/app/(editor)/lib
diff options
context:
space:
mode:
authorDhravya Shah <[email protected]>2024-06-18 17:58:46 -0500
committerDhravya Shah <[email protected]>2024-06-18 17:58:46 -0500
commitf4bb71e8f7e07bb2e919b7f222d5acb2905eb8f2 (patch)
tree7310dc521ef3559055bbe71f50c3861be2fa0503 /apps/web/app/(editor)/lib
parentdarkmode by default - so that the colors don't f up on lightmode devices (diff)
parentCreate Embeddings for Canvas (diff)
downloadsupermemory-default-darkmode.tar.xz
supermemory-default-darkmode.zip
Diffstat (limited to 'apps/web/app/(editor)/lib')
-rw-r--r--apps/web/app/(editor)/lib/content.ts231
-rw-r--r--apps/web/app/(editor)/lib/debouncedsave.ts20
-rw-r--r--apps/web/app/(editor)/lib/editorprops.ts16
-rw-r--r--apps/web/app/(editor)/lib/use-local-storage.ts27
4 files changed, 294 insertions, 0 deletions
diff --git a/apps/web/app/(editor)/lib/content.ts b/apps/web/app/(editor)/lib/content.ts
new file mode 100644
index 00000000..6464cfa1
--- /dev/null
+++ b/apps/web/app/(editor)/lib/content.ts
@@ -0,0 +1,231 @@
+export const defaultEditorContent = {
+ type: "doc",
+ content: [
+ {
+ type: "heading",
+ attrs: { level: 2 },
+ content: [{ type: "text", text: "Introducing Novel" }],
+ },
+ {
+ type: "paragraph",
+ content: [
+ {
+ type: "text",
+ marks: [
+ {
+ type: "link",
+ attrs: {
+ href: "https://github.com/steven-tey/novel",
+ target: "_blank",
+ },
+ },
+ ],
+ text: "Novel",
+ },
+ {
+ type: "text",
+ text: " is a Notion-style WYSIWYG editor with AI-powered autocompletion. Built with ",
+ },
+ {
+ type: "text",
+ marks: [
+ {
+ type: "link",
+ attrs: {
+ href: "https://tiptap.dev/",
+ target: "_blank",
+ },
+ },
+ ],
+ text: "Tiptap",
+ },
+ { type: "text", text: " + " },
+ {
+ type: "text",
+ marks: [
+ {
+ type: "link",
+ attrs: {
+ href: "https://sdk.vercel.ai/docs",
+ target: "_blank",
+ },
+ },
+ ],
+ text: "Vercel AI SDK",
+ },
+ { type: "text", text: "." },
+ ],
+ },
+ {
+ type: "heading",
+ attrs: { level: 3 },
+ content: [{ type: "text", text: "Installation" }],
+ },
+ {
+ type: "codeBlock",
+ attrs: { language: null },
+ content: [{ type: "text", text: "npm i novel" }],
+ },
+ {
+ type: "heading",
+ attrs: { level: 3 },
+ content: [{ type: "text", text: "Usage" }],
+ },
+ {
+ type: "codeBlock",
+ attrs: { language: null },
+ content: [
+ {
+ type: "text",
+ text: 'import { Editor } from "novel";\n\nexport default function App() {\n return (\n <Editor />\n )\n}',
+ },
+ ],
+ },
+ {
+ type: "heading",
+ attrs: { level: 3 },
+ content: [{ type: "text", text: "Features" }],
+ },
+ {
+ type: "orderedList",
+ attrs: { tight: true, start: 1 },
+ content: [
+ {
+ type: "listItem",
+ content: [
+ {
+ type: "paragraph",
+ content: [{ type: "text", text: "Slash menu & bubble menu" }],
+ },
+ ],
+ },
+ {
+ type: "listItem",
+ content: [
+ {
+ type: "paragraph",
+ content: [
+ { type: "text", text: "AI autocomplete (type " },
+ { type: "text", marks: [{ type: "code" }], text: "++" },
+ {
+ type: "text",
+ text: " to activate, or select from slash menu)",
+ },
+ ],
+ },
+ ],
+ },
+ {
+ type: "listItem",
+ content: [
+ {
+ type: "paragraph",
+ content: [
+ {
+ type: "text",
+ text: "Image uploads (drag & drop / copy & paste, or select from slash menu) ",
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ {
+ type: "image",
+ attrs: {
+ src: "https://public.blob.vercel-storage.com/pJrjXbdONOnAeZAZ/banner-2wQk82qTwyVgvlhTW21GIkWgqPGD2C.png",
+ alt: "banner.png",
+ title: "banner.png",
+ width: null,
+ height: null,
+ },
+ },
+ { type: "horizontalRule" },
+ {
+ type: "heading",
+ attrs: { level: 3 },
+ content: [{ type: "text", text: "Learn more" }],
+ },
+ {
+ type: "taskList",
+ content: [
+ {
+ type: "taskItem",
+ attrs: { checked: false },
+ content: [
+ {
+ type: "paragraph",
+ content: [
+ { type: "text", text: "Star us on " },
+ {
+ type: "text",
+ marks: [
+ {
+ type: "link",
+ attrs: {
+ href: "https://github.com/steven-tey/novel",
+ target: "_blank",
+ },
+ },
+ ],
+ text: "GitHub",
+ },
+ ],
+ },
+ ],
+ },
+ {
+ type: "taskItem",
+ attrs: { checked: false },
+ content: [
+ {
+ type: "paragraph",
+ content: [
+ { type: "text", text: "Install the " },
+ {
+ type: "text",
+ marks: [
+ {
+ type: "link",
+ attrs: {
+ href: "https://www.npmjs.com/package/novel",
+ target: "_blank",
+ },
+ },
+ ],
+ text: "NPM package",
+ },
+ ],
+ },
+ ],
+ },
+ {
+ type: "taskItem",
+ attrs: { checked: false },
+ content: [
+ {
+ type: "paragraph",
+ content: [
+ {
+ type: "text",
+ marks: [
+ {
+ type: "link",
+ attrs: {
+ href: "https://vercel.com/templates/next.js/novel",
+ target: "_blank",
+ },
+ },
+ ],
+ text: "Deploy your own",
+ },
+ { type: "text", text: " to Vercel" },
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ ],
+};
diff --git a/apps/web/app/(editor)/lib/debouncedsave.ts b/apps/web/app/(editor)/lib/debouncedsave.ts
new file mode 100644
index 00000000..6490c6c4
--- /dev/null
+++ b/apps/web/app/(editor)/lib/debouncedsave.ts
@@ -0,0 +1,20 @@
+import hljs from 'highlight.js'
+import { debounce } from 'tldraw';
+import { useDebouncedCallback } from "use-debounce";
+
+export const Updates = debounce(({editor, setCharsCount, setSaveStatus})=> {
+ const json = editor.getJSON();
+ setCharsCount(editor.storage.characterCount.words());
+ window.localStorage.setItem("html-content", highlightCodeblocks(editor.getHTML()));
+ window.localStorage.setItem("novel-content", JSON.stringify(json));
+ window.localStorage.setItem("markdown", editor.storage.markdown.getMarkdown());
+ setSaveStatus("Saved");
+}, 500)
+
+export const highlightCodeblocks = (content: string) => {
+ const doc = new DOMParser().parseFromString(content, 'text/html');
+ doc.querySelectorAll('pre code').forEach((el) => {
+ hljs.highlightElement(el);
+ });
+ return new XMLSerializer().serializeToString(doc);
+}; \ No newline at end of file
diff --git a/apps/web/app/(editor)/lib/editorprops.ts b/apps/web/app/(editor)/lib/editorprops.ts
new file mode 100644
index 00000000..00d89264
--- /dev/null
+++ b/apps/web/app/(editor)/lib/editorprops.ts
@@ -0,0 +1,16 @@
+import { handleCommandNavigation } from "novel/extensions";
+import { handleImageDrop, handleImagePaste } from "novel/plugins";
+import { uploadFn } from "../components/image-upload";
+import { EditorView } from "prosemirror-view";
+
+export const editorProps = {
+ handleDOMEvents: {
+ keydown: (_view: EditorView, event: KeyboardEvent) => handleCommandNavigation(event),
+ },
+ handlePaste: (view: EditorView, event: ClipboardEvent) => handleImagePaste(view, event, uploadFn),
+ handleDrop: (view: EditorView, event: DragEvent, slice, moved:boolean) => handleImageDrop(view, event, moved, uploadFn),
+ attributes: {
+ class:
+ "prose prose-lg dark:prose-invert prose-headings:font-title font-default focus:outline-none max-w-full",
+ },
+} \ No newline at end of file
diff --git a/apps/web/app/(editor)/lib/use-local-storage.ts b/apps/web/app/(editor)/lib/use-local-storage.ts
new file mode 100644
index 00000000..5f2ebeb9
--- /dev/null
+++ b/apps/web/app/(editor)/lib/use-local-storage.ts
@@ -0,0 +1,27 @@
+import { useEffect, useState } from "react";
+
+const useLocalStorage = <T>(
+ key: string,
+ initialValue: T,
+ // eslint-disable-next-line no-unused-vars
+): [T, (value: T) => void] => {
+ const [storedValue, setStoredValue] = useState(initialValue);
+
+ useEffect(() => {
+ // Retrieve from localStorage
+ const item = window.localStorage.getItem(key);
+ if (item) {
+ setStoredValue(JSON.parse(item));
+ }
+ }, [key]);
+
+ const setValue = (value: T) => {
+ // Save state
+ setStoredValue(value);
+ // Save to localStorage
+ window.localStorage.setItem(key, JSON.stringify(value));
+ };
+ return [storedValue, setValue];
+};
+
+export default useLocalStorage;