1
0
Fork 0
mirror of https://github.com/kou029w/quot.git synced 2025-01-18 16:08:03 +00:00

rich text support (experimental)

This commit is contained in:
Nebel 2022-09-07 17:03:54 +09:00
parent 23e6bf327b
commit 9af143f6ce
5 changed files with 50 additions and 28 deletions

View file

@ -12,7 +12,7 @@ async function views(fastify: FastifyInstance) {
}, },
{ {
bundle: true, bundle: true,
minify: true, minify: process.env.NODE_ENV !== "development",
entryPoints: [entryPoint], entryPoints: [entryPoint],
define: { define: {
"import.meta.env.QUOT_API_ENDPOINT": JSON.stringify( "import.meta.env.QUOT_API_ENDPOINT": JSON.stringify(

14
app/package-lock.json generated
View file

@ -11,7 +11,7 @@
"@exampledev/new.css": "^1.1.3", "@exampledev/new.css": "^1.1.3",
"@fastify/http-proxy": "^8.2.2", "@fastify/http-proxy": "^8.2.2",
"@lexical/history": "^0.4.1", "@lexical/history": "^0.4.1",
"@lexical/plain-text": "^0.4.1", "@lexical/rich-text": "^0.4.1",
"@tsconfig/node18-strictest-esm": "^1.0.1", "@tsconfig/node18-strictest-esm": "^1.0.1",
"esbuild": "^0.15.7", "esbuild": "^0.15.7",
"esbuild-register": "^3.3.3", "esbuild-register": "^3.3.3",
@ -149,10 +149,10 @@
"lexical": "0.4.1" "lexical": "0.4.1"
} }
}, },
"node_modules/@lexical/plain-text": { "node_modules/@lexical/rich-text": {
"version": "0.4.1", "version": "0.4.1",
"resolved": "https://registry.npmjs.org/@lexical/plain-text/-/plain-text-0.4.1.tgz", "resolved": "https://registry.npmjs.org/@lexical/rich-text/-/rich-text-0.4.1.tgz",
"integrity": "sha512-cNFLXhOfR0coUFGA6aPGcHr6a+Y9ZrkETMM78+XV9J8iVsKij4/katFhsqACQDna4vSfXuqjTitCRtiFaDevDg==", "integrity": "sha512-EI4ul3y1hqMp0VS/4D8aOyR41ysz1KaYgkm6PyrRXEMyK8uKmVubJP83RkOU2fWkTVtdrMjM6aeT1qX849LetA==",
"peerDependencies": { "peerDependencies": {
"@lexical/clipboard": "0.4.1", "@lexical/clipboard": "0.4.1",
"@lexical/selection": "0.4.1", "@lexical/selection": "0.4.1",
@ -1207,10 +1207,10 @@
"@lexical/utils": "0.4.1" "@lexical/utils": "0.4.1"
} }
}, },
"@lexical/plain-text": { "@lexical/rich-text": {
"version": "0.4.1", "version": "0.4.1",
"resolved": "https://registry.npmjs.org/@lexical/plain-text/-/plain-text-0.4.1.tgz", "resolved": "https://registry.npmjs.org/@lexical/rich-text/-/rich-text-0.4.1.tgz",
"integrity": "sha512-cNFLXhOfR0coUFGA6aPGcHr6a+Y9ZrkETMM78+XV9J8iVsKij4/katFhsqACQDna4vSfXuqjTitCRtiFaDevDg==", "integrity": "sha512-EI4ul3y1hqMp0VS/4D8aOyR41ysz1KaYgkm6PyrRXEMyK8uKmVubJP83RkOU2fWkTVtdrMjM6aeT1qX849LetA==",
"requires": {} "requires": {}
}, },
"@lexical/selection": { "@lexical/selection": {

View file

@ -14,7 +14,7 @@
"@exampledev/new.css": "^1.1.3", "@exampledev/new.css": "^1.1.3",
"@fastify/http-proxy": "^8.2.2", "@fastify/http-proxy": "^8.2.2",
"@lexical/history": "^0.4.1", "@lexical/history": "^0.4.1",
"@lexical/plain-text": "^0.4.1", "@lexical/rich-text": "^0.4.1",
"@tsconfig/node18-strictest-esm": "^1.0.1", "@tsconfig/node18-strictest-esm": "^1.0.1",
"esbuild": "^0.15.7", "esbuild": "^0.15.7",
"esbuild-register": "^3.3.3", "esbuild-register": "^3.3.3",

View file

@ -8,3 +8,12 @@
border-top-color: var(--nc-bg-3); border-top-color: var(--nc-bg-3);
box-shadow: 0 1px var(--nc-bg-3); box-shadow: 0 1px var(--nc-bg-3);
} }
.editor :is(h1, h2, h3, h4, h5, h6) {
padding: unset;
font-size: unset;
}
.editor p {
margin: unset;
}

View file

@ -1,17 +1,21 @@
import { import {
$createLineBreakNode,
$createParagraphNode, $createParagraphNode,
$createTextNode, $createTextNode,
$getRoot, $getRoot,
$isElementNode,
createEditor, createEditor,
} from "lexical"; } from "lexical";
import { registerHistory, createEmptyHistoryState } from "@lexical/history"; import { registerHistory, createEmptyHistoryState } from "@lexical/history";
import { registerPlainText } from "@lexical/plain-text"; import {
$createHeadingNode,
HeadingNode,
registerRichText,
} from "@lexical/rich-text";
import { onCleanup, onMount } from "solid-js"; import { onCleanup, onMount } from "solid-js";
import type Pages from "../../protocol/pages"; import type Pages from "../../protocol/pages";
import "./editor.css"; import "./editor.css";
const editor = createEditor(); const editor = createEditor({ nodes: [HeadingNode] });
function ref(el: HTMLElement) { function ref(el: HTMLElement) {
editor.setRootElement(el); editor.setRootElement(el);
@ -25,25 +29,34 @@ export default (props: {
}) => { }) => {
const initialEditorState = () => { const initialEditorState = () => {
const root = $getRoot(); const root = $getRoot();
if (root.getFirstChild()) return; for (const [i, text] of props.text.split("\n").entries()) {
const paragraphNode = $createParagraphNode(); const line = i === 0 ? $createHeadingNode("h2") : $createParagraphNode();
const text = props.text const indent = text.match(/^\s*/)?.[0]?.length ?? 0;
.split("\n") line.setIndent(indent);
.flatMap((line) => [$createTextNode(line), $createLineBreakNode()]) line.append($createTextNode(text.slice(indent)));
.slice(0, -1); root.append(line);
paragraphNode.append(...text); }
root.append(paragraphNode);
}; };
onCleanup(registerPlainText(editor, initialEditorState)); onCleanup(registerRichText(editor, initialEditorState));
onCleanup(registerHistory(editor, createEmptyHistoryState(), 333)); onCleanup(registerHistory(editor, createEmptyHistoryState(), 333));
onMount(() => { onCleanup(
onCleanup( editor.registerUpdateListener(() =>
editor.registerTextContentListener((text) => { editor.update(() => {
const [title] = text.split("\n"); const root = $getRoot();
const lines = root
.getChildren()
.map(
(line) =>
`${" ".repeat(
$isElementNode(line) ? line.getIndent() : 0
)}${line.getTextContent()}`
);
const title = lines[0];
const text = lines.join("\n");
props.onUpdatePage({ id: props.id, title: title ?? "", text }); props.onUpdatePage({ id: props.id, title: title ?? "", text });
}) })
); )
editor.focus(); );
}); onMount(() => editor.focus());
return <article ref={ref} class="editor" contenteditable />; return <article ref={ref} class="editor" contenteditable />;
}; };