src/components/ace-markdown/ace-markdown.tsx
:
import { Component, Prop, State, h } from "@stencil/core";
import ace from "ace-builds/src-min-noconflict/ace.js";
import { marked } from "marked";
@Component({
tag: "ace-markdown",
shadow: true,
})
export class AceMarkdown {
containerElement!: HTMLDivElement;
@Prop({ mutable: true })
content = "# Hello world";
private editor!: any;
editorElement!: HTMLDivElement;
@State()
fullscreen = false;
previewerElement!: HTMLDivElement;
componentDidLoad() {
ace.config.set("basePath", "/");
const editor = ace.edit(this.editorElement, {
// fontSize: "14px",
mode: "ace/mode/markdown",
// theme: "ace/theme/monokai",
value: this.content,
wrap: true,
});
this.editor = editor;
editor.renderer.attachToShadowRoot(); // !!!important
editor.on("input", () => {
this.updatePreview();
});
this.updatePreview();
}
fullscreenIcon() {
return this.fullscreen ? "-" : "+";
}
fullscreenSwitch() {
this.fullscreen = !this.fullscreen;
if (this.fullscreen) {
this.containerElement.requestFullscreen();
this.containerElement.style.height = "100vh";
} else {
document.exitFullscreen();
this.containerElement.style.height = "40vh";
}
}
render() {
return (
<div
ref={(el) => {
this.containerElement = el as HTMLDivElement;
}}
style={{ height: "40vh" }}
>
<div>
<div style={{ display: "flex", "justify-content": "end" }}>
<button
onClick={() => {
this.save();
}}
type="button"
>
下載
</button>
<button
onClick={() => {
this.fullscreenSwitch();
}}
title="全屏/還原"
type="button"
>
{this.fullscreenIcon()}
</button>
</div>
</div>
<div style={{ display: "flex", height: "100%" }}>
<div style={{ flex: "50%" }}>
<div
ref={(el) => {
this.editorElement = el as HTMLDivElement;
}}
style={{ width: "100%", height: "100%" }}
>
{this.content}
</div>
</div>
<div style={{ flex: "50%" }}>
<div
ref={(el) => {
this.previewerElement = el as HTMLDivElement;
}}
style={{ width: "100%", height: "100%", overflow: "auto" }}
/>
</div>
</div>
</div>
);
}
save() {
const fileParts = [this.content];
const blob = new Blob(fileParts, { type: "text/plain" });
const a = document.createElement("a");
a.href = URL.createObjectURL(blob);
a.download = "paper.md";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
updatePreview() {
this.content = this.editor.getValue();
this.previewerElement.innerHTML = marked(this.content).toString();
}
}
justfile
:
build:
#!/usr/bin/env bash
cp node_modules/ace-builds/src-min-noconflict/mode-markdown.js www/
cp node_modules/ace-builds/src-min-noconflict/theme-monokai.js www/