diff --git a/app/package-lock.json b/app/package-lock.json
index 61b6f08..9e73bbc 100644
--- a/app/package-lock.json
+++ b/app/package-lock.json
@@ -9,8 +9,10 @@
"version": "0.0.0",
"dependencies": {
"@exampledev/new.css": "^1.1.3",
+ "@lexical/plain-text": "^0.3.11",
"esbuild": "^0.15.5",
"esbuild-register": "^3.3.3",
+ "lexical": "^0.3.11",
"solid-js": "^1.4.8"
},
"devDependencies": {
@@ -27,6 +29,90 @@
"resolved": "https://registry.npmjs.org/@exampledev/new.css/-/new.css-1.1.3.tgz",
"integrity": "sha512-qhbGfqBRwUlM6MCSaJdUfjq86opNCMvM+6kVvs6S0kYhy0V8dKbe4rDMIklEJGuMc5QH5OuPjdCReu9I0tim2w=="
},
+ "node_modules/@lexical/clipboard": {
+ "version": "0.3.11",
+ "resolved": "https://registry.npmjs.org/@lexical/clipboard/-/clipboard-0.3.11.tgz",
+ "integrity": "sha512-ly+9R2Rccz80eV9Gu0hOi701fXIyU50t+S7OR0Ensos09oAmQPae6poFkvS3k36tH+leLgk0hRZ47pB/+ejENA==",
+ "peer": true,
+ "dependencies": {
+ "@lexical/html": "0.3.11",
+ "@lexical/list": "0.3.11",
+ "@lexical/selection": "0.3.11",
+ "@lexical/utils": "0.3.11"
+ },
+ "peerDependencies": {
+ "lexical": "0.3.11"
+ }
+ },
+ "node_modules/@lexical/html": {
+ "version": "0.3.11",
+ "resolved": "https://registry.npmjs.org/@lexical/html/-/html-0.3.11.tgz",
+ "integrity": "sha512-cw6IjI+OQr6Dwm1Mvkws0HsMOZ0lIky/DIhSt7ZAcUya+N1sis3kNIhg5Gijvpao+/n17QPgOwWS2sE7PFESmg==",
+ "peer": true,
+ "dependencies": {
+ "@lexical/selection": "0.3.11"
+ },
+ "peerDependencies": {
+ "lexical": "0.3.11"
+ }
+ },
+ "node_modules/@lexical/list": {
+ "version": "0.3.11",
+ "resolved": "https://registry.npmjs.org/@lexical/list/-/list-0.3.11.tgz",
+ "integrity": "sha512-l79kqwFRTuUx+fNxRmYaqP27tB7va/MAKoRL1Jzv1EYBZjz0fEHxpaRBG7Y5JHSMMFRQrJEhL4hKMs2EiCecvQ==",
+ "peer": true,
+ "dependencies": {
+ "@lexical/utils": "0.3.11"
+ },
+ "peerDependencies": {
+ "lexical": "0.3.11"
+ }
+ },
+ "node_modules/@lexical/plain-text": {
+ "version": "0.3.11",
+ "resolved": "https://registry.npmjs.org/@lexical/plain-text/-/plain-text-0.3.11.tgz",
+ "integrity": "sha512-AfCHJPtY0g/gknYDCU2uZ5NHASSp1Gg7Ho7OuAi3sVOuVqs+SHI+ZkeC3y7MxrGhOP3TnZ+EsltAbToEQclSDA==",
+ "peerDependencies": {
+ "@lexical/clipboard": "0.3.11",
+ "@lexical/selection": "0.3.11",
+ "@lexical/utils": "0.3.11",
+ "lexical": "0.3.11"
+ }
+ },
+ "node_modules/@lexical/selection": {
+ "version": "0.3.11",
+ "resolved": "https://registry.npmjs.org/@lexical/selection/-/selection-0.3.11.tgz",
+ "integrity": "sha512-6SlXUmLP6K2E1OQFS2QcOiGe1fZV4o1vFLynq/st7BVzpQ1/bDMp2lnsnNWyA0H6v36n+wVUvipKsyFcrDtH/w==",
+ "peer": true,
+ "peerDependencies": {
+ "lexical": "0.3.11"
+ }
+ },
+ "node_modules/@lexical/table": {
+ "version": "0.3.11",
+ "resolved": "https://registry.npmjs.org/@lexical/table/-/table-0.3.11.tgz",
+ "integrity": "sha512-/6nDug81vfs6eI3u23JTRcCny1fsJ/gjM/ljERd6+f9rP+yXbStMKIyAsWebz6ZSskoyl5LIj8Po3PParhCdGg==",
+ "peer": true,
+ "dependencies": {
+ "@lexical/utils": "0.3.11"
+ },
+ "peerDependencies": {
+ "lexical": "0.3.11"
+ }
+ },
+ "node_modules/@lexical/utils": {
+ "version": "0.3.11",
+ "resolved": "https://registry.npmjs.org/@lexical/utils/-/utils-0.3.11.tgz",
+ "integrity": "sha512-J3HQjPSYg33Yd+g/SUx9Selqn27qCmXN253+0lIEH8R8pn2A+Pe4vrk+/DSr/URuN1GUq+jjLWci3SDsA4h3xQ==",
+ "peer": true,
+ "dependencies": {
+ "@lexical/list": "0.3.11",
+ "@lexical/table": "0.3.11"
+ },
+ "peerDependencies": {
+ "lexical": "0.3.11"
+ }
+ },
"node_modules/@tsconfig/node18-strictest-esm": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@tsconfig/node18-strictest-esm/-/node18-strictest-esm-1.0.0.tgz",
@@ -97,6 +183,11 @@
"esbuild": ">=0.12 <1"
}
},
+ "node_modules/lexical": {
+ "version": "0.3.11",
+ "resolved": "https://registry.npmjs.org/lexical/-/lexical-0.3.11.tgz",
+ "integrity": "sha512-HZvQ2T3g0jWBX6MC/A0HY1N7NMvR+FrmTfR4vn6WnoCg56UPlkgIX3GKa6rCyGOAnOtykXRPJ831JWEKJUHalQ=="
+ },
"node_modules/solid-js": {
"version": "1.4.8",
"resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.4.8.tgz",
@@ -122,6 +213,68 @@
"resolved": "https://registry.npmjs.org/@exampledev/new.css/-/new.css-1.1.3.tgz",
"integrity": "sha512-qhbGfqBRwUlM6MCSaJdUfjq86opNCMvM+6kVvs6S0kYhy0V8dKbe4rDMIklEJGuMc5QH5OuPjdCReu9I0tim2w=="
},
+ "@lexical/clipboard": {
+ "version": "0.3.11",
+ "resolved": "https://registry.npmjs.org/@lexical/clipboard/-/clipboard-0.3.11.tgz",
+ "integrity": "sha512-ly+9R2Rccz80eV9Gu0hOi701fXIyU50t+S7OR0Ensos09oAmQPae6poFkvS3k36tH+leLgk0hRZ47pB/+ejENA==",
+ "peer": true,
+ "requires": {
+ "@lexical/html": "0.3.11",
+ "@lexical/list": "0.3.11",
+ "@lexical/selection": "0.3.11",
+ "@lexical/utils": "0.3.11"
+ }
+ },
+ "@lexical/html": {
+ "version": "0.3.11",
+ "resolved": "https://registry.npmjs.org/@lexical/html/-/html-0.3.11.tgz",
+ "integrity": "sha512-cw6IjI+OQr6Dwm1Mvkws0HsMOZ0lIky/DIhSt7ZAcUya+N1sis3kNIhg5Gijvpao+/n17QPgOwWS2sE7PFESmg==",
+ "peer": true,
+ "requires": {
+ "@lexical/selection": "0.3.11"
+ }
+ },
+ "@lexical/list": {
+ "version": "0.3.11",
+ "resolved": "https://registry.npmjs.org/@lexical/list/-/list-0.3.11.tgz",
+ "integrity": "sha512-l79kqwFRTuUx+fNxRmYaqP27tB7va/MAKoRL1Jzv1EYBZjz0fEHxpaRBG7Y5JHSMMFRQrJEhL4hKMs2EiCecvQ==",
+ "peer": true,
+ "requires": {
+ "@lexical/utils": "0.3.11"
+ }
+ },
+ "@lexical/plain-text": {
+ "version": "0.3.11",
+ "resolved": "https://registry.npmjs.org/@lexical/plain-text/-/plain-text-0.3.11.tgz",
+ "integrity": "sha512-AfCHJPtY0g/gknYDCU2uZ5NHASSp1Gg7Ho7OuAi3sVOuVqs+SHI+ZkeC3y7MxrGhOP3TnZ+EsltAbToEQclSDA==",
+ "requires": {}
+ },
+ "@lexical/selection": {
+ "version": "0.3.11",
+ "resolved": "https://registry.npmjs.org/@lexical/selection/-/selection-0.3.11.tgz",
+ "integrity": "sha512-6SlXUmLP6K2E1OQFS2QcOiGe1fZV4o1vFLynq/st7BVzpQ1/bDMp2lnsnNWyA0H6v36n+wVUvipKsyFcrDtH/w==",
+ "peer": true,
+ "requires": {}
+ },
+ "@lexical/table": {
+ "version": "0.3.11",
+ "resolved": "https://registry.npmjs.org/@lexical/table/-/table-0.3.11.tgz",
+ "integrity": "sha512-/6nDug81vfs6eI3u23JTRcCny1fsJ/gjM/ljERd6+f9rP+yXbStMKIyAsWebz6ZSskoyl5LIj8Po3PParhCdGg==",
+ "peer": true,
+ "requires": {
+ "@lexical/utils": "0.3.11"
+ }
+ },
+ "@lexical/utils": {
+ "version": "0.3.11",
+ "resolved": "https://registry.npmjs.org/@lexical/utils/-/utils-0.3.11.tgz",
+ "integrity": "sha512-J3HQjPSYg33Yd+g/SUx9Selqn27qCmXN253+0lIEH8R8pn2A+Pe4vrk+/DSr/URuN1GUq+jjLWci3SDsA4h3xQ==",
+ "peer": true,
+ "requires": {
+ "@lexical/list": "0.3.11",
+ "@lexical/table": "0.3.11"
+ }
+ },
"@tsconfig/node18-strictest-esm": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@tsconfig/node18-strictest-esm/-/node18-strictest-esm-1.0.0.tgz",
@@ -174,6 +327,11 @@
"integrity": "sha512-eFHOkutgIMJY5gc8LUp/7c+LLlDqzNi9T6AwCZ2WKKl3HmT+5ef3ZRyPPxDOynInML0fgaC50yszPKfPnjC0NQ==",
"requires": {}
},
+ "lexical": {
+ "version": "0.3.11",
+ "resolved": "https://registry.npmjs.org/lexical/-/lexical-0.3.11.tgz",
+ "integrity": "sha512-HZvQ2T3g0jWBX6MC/A0HY1N7NMvR+FrmTfR4vn6WnoCg56UPlkgIX3GKa6rCyGOAnOtykXRPJ831JWEKJUHalQ=="
+ },
"solid-js": {
"version": "1.4.8",
"resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.4.8.tgz",
diff --git a/app/package.json b/app/package.json
index 523811d..d94f019 100644
--- a/app/package.json
+++ b/app/package.json
@@ -12,8 +12,10 @@
"packageManager": "npm@8.15.0",
"dependencies": {
"@exampledev/new.css": "^1.1.3",
+ "@lexical/plain-text": "^0.3.11",
"esbuild": "^0.15.5",
"esbuild-register": "^3.3.3",
+ "lexical": "^0.3.11",
"solid-js": "^1.4.8"
},
"devDependencies": {
diff --git a/app/src/components/editor.css b/app/src/components/editor.css
index 66c9889..de63d91 100644
--- a/app/src/components/editor.css
+++ b/app/src/components/editor.css
@@ -1,3 +1,10 @@
.editor {
- inline-size: 100%;
+ padding: 1rem;
+ box-sizing: border-box;
+ background-color: var(--nc-bg-2);
+ color: var(--nc-tx-2);
+ border-width: 0.75rem;
+ border-top-style: solid;
+ border-top-color: var(--nc-bg-3);
+ box-shadow: 0 1px var(--nc-bg-3);
}
diff --git a/app/src/components/editor.tsx b/app/src/components/editor.tsx
index 1415199..57d515f 100644
--- a/app/src/components/editor.tsx
+++ b/app/src/components/editor.tsx
@@ -1,19 +1,43 @@
+import {
+ $createParagraphNode,
+ $createTextNode,
+ $getRoot,
+ createEditor,
+} from "lexical";
+import { registerPlainText } from "@lexical/plain-text";
+import { onCleanup, onMount } from "solid-js";
import type Pages from "../protocol/pages";
import "./editor.css";
+const editor = createEditor();
+
+function ref(el: HTMLElement) {
+ editor.setRootElement(el);
+}
+
export default (props: {
id: number;
+ title: string;
+ text: string;
onUpdatePage: (content: Pages.RequestContentPage) => void;
-}) => (
-
-);
+}) => {
+ const initialEditorState = () => {
+ const root = $getRoot();
+ if (root.getFirstChild()) return;
+ const paragraphNode = $createParagraphNode();
+ const textNode = $createTextNode(props.text);
+ paragraphNode.append(textNode);
+ root.append(paragraphNode);
+ };
+ onCleanup(registerPlainText(editor, initialEditorState));
+ onMount(() => {
+ onCleanup(
+ editor.registerTextContentListener((text) => {
+ const [title] = text.split("\n");
+ props.onUpdatePage({ id: props.id, title: title ?? "", text });
+ })
+ );
+ editor.focus();
+ });
+ return ;
+};
diff --git a/app/src/pages/page.tsx b/app/src/pages/page.tsx
index 89e5c10..31a7738 100644
--- a/app/src/pages/page.tsx
+++ b/app/src/pages/page.tsx
@@ -1,7 +1,6 @@
import { createResource } from "solid-js";
import type Pages from "../protocol/pages";
import Editor from "../components/editor";
-import Card from "../components/card";
import beforeunload from "../helpers/beforeunload";
import throttle from "../helpers/throttle";
@@ -23,6 +22,14 @@ async function updatePage(
return res.ok;
}
+async function deletePage(id: number): Promise {
+ const res = await fetch(
+ new URL(`/pages?id=eq.${id}`, import.meta.env.QUOT_API_URL),
+ { method: "DELETE" }
+ );
+ return res.ok;
+}
+
async function fetchPage(id: number): Promise {
const res = await fetch(
new URL(`/pages?id=eq.${id}`, import.meta.env.QUOT_API_URL)
@@ -32,13 +39,12 @@ async function fetchPage(id: number): Promise {
}
export default (props: { id: number }) => {
- const [page, { refetch }] = createResource(props.id, fetchPage);
+ const [page] = createResource(props.id, fetchPage);
const throttledUpdate = throttle(
async (id: number, content: Pages.RequestContentPage) => {
- if (await updatePage(id, content)) {
+ if (await (content.text ? updatePage(id, content) : deletePage(id))) {
unblock();
- refetch();
- window.history.replaceState({}, "", `/${id}`);
+ window.history.replaceState({}, "", `/${content.text ? id : "new"}`);
}
},
intervalMs
@@ -51,8 +57,17 @@ export default (props: { id: number }) => {
return (
-
- {() => }
+ {() =>
+ !page.loading && (
+
+ )
+ }
);
};