From dcdc1927153e34b5634f07d88fd991e2d4572432 Mon Sep 17 00:00:00 2001 From: Visal In Date: Sun, 21 Jul 2024 19:17:29 +0900 Subject: [PATCH 1/2] experiment with making our own markdown editor --- package-lock.json | 264 ++++++++++++++++++ package.json | 3 + src/app/testing/page.tsx | 9 + .../gui/providers/full-editor-provider.tsx | 119 ++++++++ src/components/gui/query-result-table.tsx | 31 ++ src/components/gui/studio.tsx | 5 +- src/components/markdown-editor/index.tsx | 107 +++++++ 7 files changed, 537 insertions(+), 1 deletion(-) create mode 100644 src/app/testing/page.tsx create mode 100644 src/components/gui/providers/full-editor-provider.tsx create mode 100644 src/components/markdown-editor/index.tsx diff --git a/package-lock.json b/package-lock.json index fabae454..95d4c984 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,8 @@ "@dnd-kit/core": "^6.1.0", "@dnd-kit/sortable": "^8.0.0", "@justmiracle/result": "^1.2.0", + "@lexical/markdown": "^0.16.1", + "@lexical/react": "^0.16.1", "@lezer/common": "^1.2.1", "@lezer/lr": "^1.4.0", "@libsql/client": "^0.5.3", @@ -62,6 +64,7 @@ "drizzle-orm": "^0.30.1", "eslint-plugin-jest": "^27.6.3", "file-saver": "^2.0.5", + "lexical": "^0.16.1", "libsql-stateless-easy": "^1.6.11", "lucia": "^3.2.0", "lucide-react": "^0.309.0", @@ -3802,6 +3805,239 @@ "resolved": "https://registry.npmjs.org/@justmiracle/result/-/result-1.2.0.tgz", "integrity": "sha512-MyyfTSloRNvdB1EnzSDiOeyPtdXeK+gp1d2zxqcjq/XHoagsIzo7ImEJCKIUkOTlmuEInPfYZrcAU7sdeCWqkg==" }, + "node_modules/@lexical/clipboard": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@lexical/clipboard/-/clipboard-0.16.1.tgz", + "integrity": "sha512-0dWs/SwKS5KPpuf6fUVVt9vSCl6HAqcDGhSITw/okv0rrIlXTUT6WhVsMJtXfFxTyVvwMeOecJHvQH3i/jRQtA==", + "dependencies": { + "@lexical/html": "0.16.1", + "@lexical/list": "0.16.1", + "@lexical/selection": "0.16.1", + "@lexical/utils": "0.16.1", + "lexical": "0.16.1" + } + }, + "node_modules/@lexical/code": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@lexical/code/-/code-0.16.1.tgz", + "integrity": "sha512-pOC28rRZ2XkmI2nIJm50DbKaCJtk5D0o7r6nORYp4i0z+lxt5Sf2m82DL9ksUHJRqKy87pwJDpoWvJ2SAI0ohw==", + "dependencies": { + "@lexical/utils": "0.16.1", + "lexical": "0.16.1", + "prismjs": "^1.27.0" + } + }, + "node_modules/@lexical/devtools-core": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@lexical/devtools-core/-/devtools-core-0.16.1.tgz", + "integrity": "sha512-8CvGERGL7ySDVGLU+YPeq+JupIXsOFlXa3EuJ88koLKqXxYenwMleZgGqayFp6lCP78xqPKnATVeoOZUt/NabQ==", + "dependencies": { + "@lexical/html": "0.16.1", + "@lexical/link": "0.16.1", + "@lexical/mark": "0.16.1", + "@lexical/table": "0.16.1", + "@lexical/utils": "0.16.1", + "lexical": "0.16.1" + }, + "peerDependencies": { + "react": ">=17.x", + "react-dom": ">=17.x" + } + }, + "node_modules/@lexical/dragon": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@lexical/dragon/-/dragon-0.16.1.tgz", + "integrity": "sha512-Rvd60GIYN5kpjjBumS34EnNbBaNsoseI0AlzOdtIV302jiHPCLH0noe9kxzu9nZy+MZmjZy8Dx2zTbQT2mueRw==", + "dependencies": { + "lexical": "0.16.1" + } + }, + "node_modules/@lexical/hashtag": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@lexical/hashtag/-/hashtag-0.16.1.tgz", + "integrity": "sha512-G+YOxStAKs3q1utqm9KR4D4lCkwIH52Rctm4RgaVTI+4lvTaybeDRGFV75P/pI/qlF7/FvAYHTYEzCjtC3GNMQ==", + "dependencies": { + "@lexical/utils": "0.16.1", + "lexical": "0.16.1" + } + }, + "node_modules/@lexical/history": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@lexical/history/-/history-0.16.1.tgz", + "integrity": "sha512-WQhScx0TJeKSQAnEkRpIaWdUXqirrNrom2MxbBUc/32zEUMm9FzV7nRGknvUabEFUo7vZq6xTZpOExQJqHInQA==", + "dependencies": { + "@lexical/utils": "0.16.1", + "lexical": "0.16.1" + } + }, + "node_modules/@lexical/html": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@lexical/html/-/html-0.16.1.tgz", + "integrity": "sha512-vbtAdCvQ3PaAqa5mFmtmrvbiAvjCu1iXBAJ0bsHqFXCF2Sba5LwHVe8dUAOTpfEZEMbiHfjul6b5fj4vNPGF2A==", + "dependencies": { + "@lexical/selection": "0.16.1", + "@lexical/utils": "0.16.1", + "lexical": "0.16.1" + } + }, + "node_modules/@lexical/link": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@lexical/link/-/link-0.16.1.tgz", + "integrity": "sha512-zG36gEnEqbIe6tK/MhXi7wn/XMY/zdivnPcOY5WyC3derkEezeLSSIFsC1u5UNeK5pbpNMSy4LDpLhi1Ww4Y5w==", + "dependencies": { + "@lexical/utils": "0.16.1", + "lexical": "0.16.1" + } + }, + "node_modules/@lexical/list": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@lexical/list/-/list-0.16.1.tgz", + "integrity": "sha512-i9YhLAh5N6YO9dP+R1SIL9WEdCKeTiQQYVUzj84vDvX5DIBxMPUjTmMn3LXu9T+QO3h1s2L/vJusZASrl45eAw==", + "dependencies": { + "@lexical/utils": "0.16.1", + "lexical": "0.16.1" + } + }, + "node_modules/@lexical/mark": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@lexical/mark/-/mark-0.16.1.tgz", + "integrity": "sha512-CZRGMLcxn5D+jzf1XnH+Z+uUugmpg1mBwTbGybCPm8UWpBrKDHkrscfMgWz62iRWz0cdVjM5+0zWpNElxFTRjQ==", + "dependencies": { + "@lexical/utils": "0.16.1", + "lexical": "0.16.1" + } + }, + "node_modules/@lexical/markdown": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@lexical/markdown/-/markdown-0.16.1.tgz", + "integrity": "sha512-0sBLttMvfQO/hVaIqpHdvDowpgV2CoRuWo2CNwvRLZPPWvPVjL4Nkb73wmi8zAZsAOTbX2aw+g4m/+k5oJqNig==", + "dependencies": { + "@lexical/code": "0.16.1", + "@lexical/link": "0.16.1", + "@lexical/list": "0.16.1", + "@lexical/rich-text": "0.16.1", + "@lexical/text": "0.16.1", + "@lexical/utils": "0.16.1", + "lexical": "0.16.1" + } + }, + "node_modules/@lexical/offset": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@lexical/offset/-/offset-0.16.1.tgz", + "integrity": "sha512-/i2J04lQmFeydUZIF8tKXLQTXiJDTQ6GRnkfv1OpxU4amc0rwGa7+qAz/PuF1n58rP6InpLmSHxgY5JztXa2jw==", + "dependencies": { + "lexical": "0.16.1" + } + }, + "node_modules/@lexical/overflow": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@lexical/overflow/-/overflow-0.16.1.tgz", + "integrity": "sha512-xh5YpoxwA7K4wgMQF/Sjl8sdjaxqesLCtH5ZrcMsaPlmucDIEEs+i8xxk+kDUTEY7y+3FvRxs4lGNgX8RVWkvQ==", + "dependencies": { + "lexical": "0.16.1" + } + }, + "node_modules/@lexical/plain-text": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@lexical/plain-text/-/plain-text-0.16.1.tgz", + "integrity": "sha512-GjY4ylrBZIaAVIF8IFnmW0XGyHAuRmWA6gKB8iTTlsjgFrCHFIYC74EeJSp309O0Hflg9rRBnKoX1TYruFHVwA==", + "dependencies": { + "@lexical/clipboard": "0.16.1", + "@lexical/selection": "0.16.1", + "@lexical/utils": "0.16.1", + "lexical": "0.16.1" + } + }, + "node_modules/@lexical/react": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@lexical/react/-/react-0.16.1.tgz", + "integrity": "sha512-SsGgLt9iKfrrMRy9lFb6ROVPUYOgv6b+mCn9Al+TLqs/gBReDBi3msA7m526nrtBUKYUnjHdQ1QXIJzuKgOxcg==", + "dependencies": { + "@lexical/clipboard": "0.16.1", + "@lexical/code": "0.16.1", + "@lexical/devtools-core": "0.16.1", + "@lexical/dragon": "0.16.1", + "@lexical/hashtag": "0.16.1", + "@lexical/history": "0.16.1", + "@lexical/link": "0.16.1", + "@lexical/list": "0.16.1", + "@lexical/mark": "0.16.1", + "@lexical/markdown": "0.16.1", + "@lexical/overflow": "0.16.1", + "@lexical/plain-text": "0.16.1", + "@lexical/rich-text": "0.16.1", + "@lexical/selection": "0.16.1", + "@lexical/table": "0.16.1", + "@lexical/text": "0.16.1", + "@lexical/utils": "0.16.1", + "@lexical/yjs": "0.16.1", + "lexical": "0.16.1", + "react-error-boundary": "^3.1.4" + }, + "peerDependencies": { + "react": ">=17.x", + "react-dom": ">=17.x" + } + }, + "node_modules/@lexical/rich-text": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@lexical/rich-text/-/rich-text-0.16.1.tgz", + "integrity": "sha512-4uEVXJur7tdSbqbmsToCW4YVm0AMh4y9LK077Yq2O9hSuA5dqpI8UbTDnxZN2D7RfahNvwlqp8eZKFB1yeiJGQ==", + "dependencies": { + "@lexical/clipboard": "0.16.1", + "@lexical/selection": "0.16.1", + "@lexical/utils": "0.16.1", + "lexical": "0.16.1" + } + }, + "node_modules/@lexical/selection": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@lexical/selection/-/selection-0.16.1.tgz", + "integrity": "sha512-+nK3RvXtyQvQDq7AZ46JpphmM33pwuulwiRfeXR5T9iFQTtgWOEjsAi/KKX7vGm70BxACfiSxy5QCOgBWFwVJg==", + "dependencies": { + "lexical": "0.16.1" + } + }, + "node_modules/@lexical/table": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@lexical/table/-/table-0.16.1.tgz", + "integrity": "sha512-GWb0/MM1sVXpi1p2HWWOBldZXASMQ4c6WRNYnRmq7J/aB5N66HqQgJGKp3m66Kz4k1JjhmZfPs7F018qIBhnFQ==", + "dependencies": { + "@lexical/utils": "0.16.1", + "lexical": "0.16.1" + } + }, + "node_modules/@lexical/text": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@lexical/text/-/text-0.16.1.tgz", + "integrity": "sha512-Os/nKQegORTrKKN6vL3/FMVszyzyqaotlisPynvTaHTUC+yY4uyjM2hlF93i5a2ixxyiPLF9bDroxUP96TMPXg==", + "dependencies": { + "lexical": "0.16.1" + } + }, + "node_modules/@lexical/utils": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@lexical/utils/-/utils-0.16.1.tgz", + "integrity": "sha512-BVyJxDQi/rIxFTDjf2zE7rMDKSuEaeJ4dybHRa/hRERt85gavGByQawSLeQlTjLaYLVsy+x7wCcqh2fNhlLf0g==", + "dependencies": { + "@lexical/list": "0.16.1", + "@lexical/selection": "0.16.1", + "@lexical/table": "0.16.1", + "lexical": "0.16.1" + } + }, + "node_modules/@lexical/yjs": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@lexical/yjs/-/yjs-0.16.1.tgz", + "integrity": "sha512-QHw1bmzB/IypIV1tRWMH4hhwE1xX7wV+HxbzBS8oJAkoU5AYXM/kyp/sQicgqiwVfpai1Px7zatOoUDFgbyzHQ==", + "dependencies": { + "@lexical/offset": "0.16.1", + "lexical": "0.16.1" + }, + "peerDependencies": { + "yjs": ">=13.5.22" + } + }, "node_modules/@lezer/common": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.1.tgz", @@ -15504,6 +15740,11 @@ "node": ">= 0.8.0" } }, + "node_modules/lexical": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/lexical/-/lexical-0.16.1.tgz", + "integrity": "sha512-+R05d3+N945OY8pTUjTqQrWoApjC+ctzvjnmNETtx9WmVAaiW0tQVG+AYLt5pDGY8dQXtd4RPorvnxBTECt9SA==" + }, "node_modules/lib0": { "version": "0.2.94", "resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.94.tgz", @@ -20645,6 +20886,14 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "engines": { + "node": ">=6" + } + }, "node_modules/prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -20953,6 +21202,21 @@ "react": "^18.3.1" } }, + "node_modules/react-error-boundary": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-3.1.4.tgz", + "integrity": "sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + }, + "peerDependencies": { + "react": ">=16.13.1" + } + }, "node_modules/react-icons": { "version": "4.12.0", "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.12.0.tgz", diff --git a/package.json b/package.json index d1b8641d..6f22eca6 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,8 @@ "@dnd-kit/core": "^6.1.0", "@dnd-kit/sortable": "^8.0.0", "@justmiracle/result": "^1.2.0", + "@lexical/markdown": "^0.16.1", + "@lexical/react": "^0.16.1", "@lezer/common": "^1.2.1", "@lezer/lr": "^1.4.0", "@libsql/client": "^0.5.3", @@ -81,6 +83,7 @@ "drizzle-orm": "^0.30.1", "eslint-plugin-jest": "^27.6.3", "file-saver": "^2.0.5", + "lexical": "^0.16.1", "libsql-stateless-easy": "^1.6.11", "lucia": "^3.2.0", "lucide-react": "^0.309.0", diff --git a/src/app/testing/page.tsx b/src/app/testing/page.tsx new file mode 100644 index 00000000..d8172b17 --- /dev/null +++ b/src/app/testing/page.tsx @@ -0,0 +1,9 @@ +import MarkdownEditor from "@/components/markdown-editor"; + +export default function TestingPage() { + return ( +
+ +
+ ); +} diff --git a/src/components/gui/providers/full-editor-provider.tsx b/src/components/gui/providers/full-editor-provider.tsx new file mode 100644 index 00000000..27777678 --- /dev/null +++ b/src/components/gui/providers/full-editor-provider.tsx @@ -0,0 +1,119 @@ +import { Button } from "@/components/ui/button"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { Separator } from "@/components/ui/separator"; +import { Sheet, SheetContent } from "@/components/ui/sheet"; +import { noop } from "@/lib/utils"; +import { + createContext, + Fragment, + PropsWithChildren, + useContext, + useMemo, + useState, +} from "react"; + +interface FullEditorContextValue { + openEditor: (option: FullEditorOption) => void; + closeEditor: () => void; +} + +interface FullEditorOption { + initialValue: string; + onSave: (value: string) => void; + onCancel: () => void; +} + +const FullEditorContext = createContext({ + openEditor: noop, + closeEditor: noop, +}); + +function FullEditorSheet({ option }: { option: FullEditorOption }) { + const [value, setValue] = useState(option.initialValue); + + return ( + + +
+
+
+ +
+
+ + +
+ +