diff --git a/plugs/markdown/assets/markdown_widget.css b/plugs/markdown/assets/markdown_widget.css
index 0090b0e..92e06e6 100644
--- a/plugs/markdown/assets/markdown_widget.css
+++ b/plugs/markdown/assets/markdown_widget.css
@@ -25,10 +25,29 @@ body {
color: var(--root-color);
}
-ul li p {
- margin: 0;
+ul,
+ol {
+ margin-top: 0;
+ margin-bottom: 0;
}
+ul {
+ list-style: none;
+}
+
+ul li::before {
+ content: "\2022";
+ /* Add content: \2022 is the CSS Code/unicode for a bullet */
+ color: var(--editor-list-bullet-color);
+ display: inline-block;
+ /* Needed to add space between the bullet and the text */
+ width: 1em;
+ /* Also needed for space (tweak if needed) */
+ margin-left: -1em;
+ /* Also needed for space (tweak if needed) */
+}
+
+
body:hover #button-bar,
body:active #button-bar {
display: block;
diff --git a/plugs/markdown/html_render.ts b/plugs/markdown/html_render.ts
index 14d09e5..1a9a55e 100644
--- a/plugs/markdown/html_render.ts
+++ b/plugs/markdown/html_render.ts
@@ -7,10 +7,18 @@ export type Tag = {
} | string;
function htmlEscape(s: string): string {
- return s.replace(/&/g, "&")
+ s = s.replace(/&/g, "&")
.replace(//g, ">")
- .replace(/"/g, """);
+ .replace(/"/g, """)
+ .replace(/\n/g, "
");
+
+ let oldS = s;
+ do {
+ oldS = s;
+ s = s.replace(/ /g, " ");
+ } while (s !== oldS);
+ return s;
}
export function renderHtml(t: Tag | null): string {
@@ -33,9 +41,9 @@ export function renderHtml(t: Tag | null): string {
if (t.name === Fragment) {
return body;
}
- if (t.body) {
- return `<${t.name}${attrs}>${body}${t.name}>`;
- } else {
- return `<${t.name}${attrs}/>`;
- }
+ // if (t.body) {
+ return `<${t.name}${attrs}>${body}${t.name}>`;
+ // } else {
+ // return `<${t.name}${attrs}/>`;
+ // }
}
diff --git a/plugs/markdown/markdown_render.test.ts b/plugs/markdown/markdown_render.test.ts
index 5b06ade..78a475b 100644
--- a/plugs/markdown/markdown_render.test.ts
+++ b/plugs/markdown/markdown_render.test.ts
@@ -29,17 +29,37 @@ Deno.test("Markdown render", async () => {
await system.unloadAll();
});
-Deno.test("Smart hard break test", async () => {
+Deno.test("Smart hard break test", () => {
const example = `**Hello**
*world!*`;
const lang = buildMarkdown([]);
const tree = parse(lang, example);
- const html = renderMarkdownToHtml(tree, {
+ const html = renderMarkdownToHtml(tree, {
failOnUnknown: true,
smartHardBreak: true,
});
- assertEquals(
- html,
- `
Hello
world!
`,
- );
+ // assertEquals(
+ // html,
+ // `Hello
world!`,
+ // );
+
+ const example2 = `This is going to be a text. With a new line.
+
+And another
+
+* and a list
+* with a second item
+
+### [[Bla]]
+ Url: something
+ Server: something else
+ 📅 last_updated - [Release notes](release_notes_url)`;
+
+ const tree2 = parse(lang, example2);
+ const html2 = renderMarkdownToHtml(tree2, {
+ failOnUnknown: true,
+ smartHardBreak: true,
+ });
+
+ console.log(html2);
});
diff --git a/plugs/markdown/markdown_render.ts b/plugs/markdown/markdown_render.ts
index 992d7f7..2095ab8 100644
--- a/plugs/markdown/markdown_render.ts
+++ b/plugs/markdown/markdown_render.ts
@@ -1,4 +1,5 @@
import {
+ addParentPointers,
collectNodesOfType,
findNodeOfType,
ParseTree,
@@ -17,9 +18,12 @@ type MarkdownRenderOptions = {
translateUrls?: (url: string) => string;
};
-function cleanTags(values: (Tag | null)[]): Tag[] {
+function cleanTags(values: (Tag | null)[], cleanWhitespace = false): Tag[] {
const result: Tag[] = [];
for (const value of values) {
+ if (cleanWhitespace && typeof value === "string" && value.match(/^\s+$/)) {
+ continue;
+ }
if (value) {
result.push(value);
}
@@ -28,12 +32,13 @@ function cleanTags(values: (Tag | null)[]): Tag[] {
}
function preprocess(t: ParseTree, options: MarkdownRenderOptions = {}) {
+ addParentPointers(t);
traverseTree(t, (node) => {
- if (node.type === "Paragraph" && options.smartHardBreak) {
- for (const child of node.children!) {
- // If at the paragraph level there's a newline, let's turn it into a hard break
- if (!child.type && child.text === "\n") {
- child.type = "HardBreak";
+ if (!node.type) {
+ if (node.text?.startsWith("\n")) {
+ const prevNodeIdx = node.parent!.children!.indexOf(node) - 1;
+ if (node.parent!.children![prevNodeIdx]?.type !== "Paragraph") {
+ node.text = node.text.slice(1);
}
}
}
@@ -109,7 +114,10 @@ function render(
};
case "Paragraph":
return {
- name: "p",
+ name: "span",
+ attrs: {
+ class: "p",
+ },
body: cleanTags(mapRender(t.children!)),
};
// Code blocks
@@ -167,17 +175,17 @@ function render(
case "BulletList":
return {
name: "ul",
- body: cleanTags(mapRender(t.children!)),
+ body: cleanTags(mapRender(t.children!), true),
};
case "OrderedList":
return {
name: "ol",
- body: cleanTags(mapRender(t.children!)),
+ body: cleanTags(mapRender(t.children!), true),
};
case "ListItem":
return {
name: "li",
- body: cleanTags(mapRender(t.children!)),
+ body: cleanTags(mapRender(t.children!), true),
};
case "StrongEmphasis":
return {
diff --git a/web/styles/editor.scss b/web/styles/editor.scss
index 190c292..3a34aeb 100644
--- a/web/styles/editor.scss
+++ b/web/styles/editor.scss
@@ -392,7 +392,6 @@
font-weight: normal;
margin-bottom: -3rem;
overflow: auto;
-
}
table {