WIP 2
This commit is contained in:
parent
be067e5008
commit
9450945143
File diff suppressed because it is too large
Load Diff
|
@ -30,6 +30,7 @@
|
|||
"@types/marked": "4.0.3",
|
||||
"@types/papaparse": "5.2.5",
|
||||
"@types/qrcode": "1.4.1",
|
||||
"@types/turndown": "5.0.1",
|
||||
"@types/ua-parser-js": "0.7.36",
|
||||
"@types/workbox-precaching": "4.3.1",
|
||||
"@types/workbox-sw": "4.3.1",
|
||||
|
@ -49,6 +50,7 @@
|
|||
"papaparse": "5.3.1",
|
||||
"qrcode": "1.5.0",
|
||||
"reflect-metadata": "0.1.13",
|
||||
"turndown": "7.1.1",
|
||||
"typescript": "4.4.3",
|
||||
"ua-parser-js": "0.7.28",
|
||||
"workbox-precaching": "6.2.0",
|
||||
|
|
|
@ -18,6 +18,7 @@ import { descriptionForAudit, iconForAudit, titleTextForAudit } from "../lib/aud
|
|||
import "./popover";
|
||||
import "./rich-input";
|
||||
import "./rich-content";
|
||||
import { RichInput } from "./rich-input";
|
||||
|
||||
@customElement("pl-field")
|
||||
export class FieldElement extends LitElement {
|
||||
|
@ -218,12 +219,15 @@ export class FieldElement extends LitElement {
|
|||
.value-display {
|
||||
display: block;
|
||||
margin: 0 0.4em 0.4em 1.5em;
|
||||
white-space: pre-wrap;
|
||||
overflow-wrap: break-word;
|
||||
user-select: text;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
pre.value-display {
|
||||
white-space: pre-wrap;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
.value-display.small {
|
||||
margin-left: 1.8em;
|
||||
}
|
||||
|
@ -262,7 +266,7 @@ export class FieldElement extends LitElement {
|
|||
case "note":
|
||||
return html` <pl-rich-content
|
||||
class="small value-display"
|
||||
type="html"
|
||||
type="markdown"
|
||||
.content=${this.field.value}
|
||||
></pl-rich-content>`;
|
||||
default:
|
||||
|
@ -276,7 +280,7 @@ export class FieldElement extends LitElement {
|
|||
return html`
|
||||
<pl-rich-input
|
||||
class="small value-input"
|
||||
@input=${() => (this.field.value = this._valueInput.value)}
|
||||
@input=${(e: Event) => (this.field.value = (e.target! as RichInput).value)}
|
||||
.value=${this.field.value}
|
||||
>
|
||||
</pl-rich-input>
|
||||
|
|
|
@ -610,6 +610,10 @@ export class PlIcon extends LitElement {
|
|||
content: "\\f033";
|
||||
}
|
||||
|
||||
:host([icon="strikethrough"]) > div::before {
|
||||
content: "\\f0cc";
|
||||
}
|
||||
|
||||
:host([icon="list"]) > div::before {
|
||||
content: "\\f03a";
|
||||
}
|
||||
|
|
|
@ -733,7 +733,7 @@ export class ItemsList extends StateMixin(LitElement) {
|
|||
|
||||
<div class="horizontal layout">
|
||||
<pl-button class="slim transparent" @click=${() => (this.multiSelect = true)}>
|
||||
<pl-icon icon="checked"></pl-icon>
|
||||
<pl-icon icon="list-check"></pl-icon>
|
||||
</pl-button>
|
||||
|
||||
<pl-button
|
||||
|
|
|
@ -3,7 +3,7 @@ import { sanitize } from "dompurify";
|
|||
import { html, LitElement } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
import { unsafeHTML } from "lit/directives/unsafe-html.js";
|
||||
import { mardownToHtml } from "../lib/markdown";
|
||||
import { markdownToLitTemplate } from "../lib/markdown";
|
||||
import { content, shared } from "../styles";
|
||||
import { icons } from "../styles/icons";
|
||||
|
||||
|
@ -37,7 +37,7 @@ export class RichContent extends LitElement {
|
|||
render() {
|
||||
switch (this.type) {
|
||||
case "markdown":
|
||||
return mardownToHtml(this.content, this.sanitize);
|
||||
return markdownToLitTemplate(this.content, this.sanitize);
|
||||
case "html":
|
||||
const content = this.sanitize
|
||||
? sanitize(this.content, { ADD_TAGS: ["pl-icon"], ADD_ATTR: ["icon"] })
|
||||
|
|
|
@ -6,23 +6,28 @@ import "./button";
|
|||
import "./icon";
|
||||
import "./list";
|
||||
import "./popover";
|
||||
// import { EmojiClickEvent } from "./emoji-picker";
|
||||
// import "./emoji-picker";
|
||||
import { htmlToMarkdown, markdownToHtml } from "../lib/markdown";
|
||||
|
||||
@customElement("pl-rich-input")
|
||||
export class RichInput extends LitElement {
|
||||
get value() {
|
||||
return this._editor.getHTML();
|
||||
const html = this._editor.getHTML();
|
||||
const md = htmlToMarkdown(html);
|
||||
return md;
|
||||
}
|
||||
|
||||
set value(content: string) {
|
||||
const html = markdownToHtml(content).replace(/\n/g, "");
|
||||
this._editor.commands.clearContent();
|
||||
this._editor.commands.insertContent(content);
|
||||
this._editor.commands.insertContent(html);
|
||||
}
|
||||
|
||||
private _editor = new Editor({
|
||||
extensions: [StarterKit],
|
||||
onTransaction: () => this.requestUpdate(),
|
||||
onTransaction: () => {
|
||||
this.requestUpdate();
|
||||
this.dispatchEvent(new CustomEvent("input"));
|
||||
},
|
||||
onFocus: () => this.classList.add("focused"),
|
||||
onBlur: () => this.classList.remove("focused"),
|
||||
});
|
||||
|
@ -36,13 +41,6 @@ export class RichInput extends LitElement {
|
|||
this._editor.commands.focus();
|
||||
}
|
||||
|
||||
// private _emojiSelected(e: EmojiClickEvent) {
|
||||
// console.log(e);
|
||||
// if (e.detail.unicode) {
|
||||
// this._editor.chain().focus().insertContent(e.detail.unicode).run();
|
||||
// }
|
||||
// }
|
||||
|
||||
static styles = [
|
||||
shared,
|
||||
content,
|
||||
|
@ -150,14 +148,6 @@ export class RichInput extends LitElement {
|
|||
<pl-icon icon="list-ol"></pl-icon>
|
||||
</pl-button>
|
||||
|
||||
<pl-button
|
||||
class="transparent slim"
|
||||
.toggled=${this._editor?.isActive("orderedList")}
|
||||
@click=${() => this._editor.chain().focus().toggleOrderedList().run()}
|
||||
>
|
||||
<pl-icon icon="list-check"></pl-icon>
|
||||
</pl-button>
|
||||
|
||||
<pl-button
|
||||
class="transparent slim"
|
||||
.toggled=${this._editor?.isActive("blockquote")}
|
||||
|
|
|
@ -1,8 +1,53 @@
|
|||
import { addHook, sanitize } from "dompurify";
|
||||
import { marked } from "marked";
|
||||
import TurnDown from "turndown";
|
||||
import { unsafeHTML } from "lit/directives/unsafe-html.js";
|
||||
import { html } from "lit";
|
||||
|
||||
const turndown = new TurnDown({
|
||||
// blankReplacement: (_content, node) => {
|
||||
// return node.nodeName === "P" ? `<p> </p>\n` : "";
|
||||
// },
|
||||
});
|
||||
turndown.addRule("p", {
|
||||
filter: "p",
|
||||
replacement: (content, node) => {
|
||||
if (node.nextSibling) {
|
||||
content = content + "\n\n";
|
||||
}
|
||||
if (node.previousSibling) {
|
||||
content = "\n\n" + content;
|
||||
}
|
||||
return content;
|
||||
},
|
||||
});
|
||||
|
||||
turndown.addRule("strikethrough", {
|
||||
filter: ["s"],
|
||||
replacement: function (content) {
|
||||
return "~" + content + "~";
|
||||
},
|
||||
});
|
||||
|
||||
turndown.addRule("li", {
|
||||
filter: "li",
|
||||
replacement: (content, node, options) => {
|
||||
content = content
|
||||
.replace(/^\n+/, "") // remove leading newlines
|
||||
.replace(/\n+$/, "\n") // replace trailing newlines with just a single one
|
||||
.replace(/\n/gm, "\n "); // indent
|
||||
|
||||
var prefix = options.bulletListMarker + " ";
|
||||
var parent = node.parentNode as HTMLElement | null;
|
||||
if (parent?.nodeName === "OL") {
|
||||
var start = parent.getAttribute("start");
|
||||
var index = Array.prototype.indexOf.call(parent.children, node);
|
||||
prefix = (start ? Number(start) + index : index + 1) + ". ";
|
||||
}
|
||||
return prefix + content + (node.nextSibling && !/\n$/.test(content) ? "\n" : "");
|
||||
},
|
||||
});
|
||||
|
||||
// Add a hook to make all links open a new window
|
||||
addHook("afterSanitizeAttributes", function (node) {
|
||||
// set all elements owning target to target=_blank
|
||||
|
@ -11,12 +56,21 @@ addHook("afterSanitizeAttributes", function (node) {
|
|||
}
|
||||
});
|
||||
|
||||
export function mardownToHtml(md: string, san = true) {
|
||||
export function markdownToHtml(md: string, san = true) {
|
||||
let markup = marked(md, {
|
||||
headerIds: false,
|
||||
});
|
||||
if (san) {
|
||||
markup = sanitize(markup);
|
||||
}
|
||||
return markup;
|
||||
}
|
||||
|
||||
export function htmlToMarkdown(html: string) {
|
||||
return turndown.turndown(html);
|
||||
}
|
||||
|
||||
export function markdownToLitTemplate(md: string, san = true) {
|
||||
const markup = markdownToHtml(md, san);
|
||||
return html`${unsafeHTML(markup)}`;
|
||||
}
|
||||
|
|
|
@ -190,7 +190,7 @@ export const FIELD_DEFS: { [t in FieldType]: FieldDef } = {
|
|||
return $l("Note");
|
||||
},
|
||||
format(value: string) {
|
||||
return value.replace(/(<([^>]+)>)/gi, " ");
|
||||
return value.split("\n")[0] || "";
|
||||
},
|
||||
},
|
||||
[FieldType.Text]: {
|
||||
|
|
Loading…
Reference in New Issue