Added markdown rendering

This commit is contained in:
Magnus Åhall 2026-05-15 08:22:43 +02:00
parent 26ca510785
commit 5a0340c226
172 changed files with 12198 additions and 8338 deletions

View file

@ -1,12 +1,33 @@
import { ROOT_NODE } from 'node_store'
import { CustomHTMLElement } from './lib/custom_html_element.mjs'
import { MarkedPosition } from './marked_position.mjs'
export class N2NodeUI extends CustomHTMLElement {
static {// {{{
this.tmpl = document.createElement('template')
this.tmpl.innerHTML = `
<style>
.el-functions {
display: grid;
grid-template-columns: 1fr min-content;
grid-gap: 8px;
align-items: center;
justify-items: end;
img {
height: 24px;
}
}
</style>
<div data-el="name"></div>
<textarea data-el="node-content" required rows=1></textarea>
<div data-el="node-markdown"></div>
<div data-el="functions">
<img data-el="icon-markdown">
<img data-el="icon-save" src="/images/${_VERSION}/icon_save_disabled.svg">
</div>
`
}// }}}
@ -15,6 +36,8 @@ export class N2NodeUI extends CustomHTMLElement {
this.node = null
this.style.display = 'contents'
this.classList.add('show-markdown') // TODO Should probably be moved to settings.
this.marked = new MarkedPosition()
_mbus.subscribe('NODE_UI_OPEN', event => {
this.node = event.detail.data
@ -23,17 +46,26 @@ export class N2NodeUI extends CustomHTMLElement {
_mbus.subscribe('NODE_MODIFIED', () => {
document.querySelector('#crumbs .crumbs')?.classList.add('node-modified')
this.elIconSave.src = `/images/${_VERSION}/icon_save.svg`
})
_mbus.subscribe('NODE_UNMODIFIED', () => {
document.querySelector('#crumbs .crumbs')?.classList.remove('node-modified')
this.elIconSave.src = `/images/${_VERSION}/icon_save_disabled.svg`
})
_mbus.subscribe('MARKDOWN_TOGGLE', () => this.showMarkdown(!this.showMarkdown()))
_mbus.subscribe('MARKDOWN_EDIT', ({detail}) => this.editMarkdown(detail.data))
this.elNodeContent.addEventListener('input', event => this.contentChanged(event))
this.elIconMarkdown.addEventListener('click', () => this.showMarkdown(!this.showMarkdown()))
this.showMarkdown(true)
}// }}}
render() {// {{{
this.elName.innerText = this.node?.get('Name') ?? ''
this.elNodeContent.value = this.node?.get('Content') ?? ''
this.elNodeMarkdown.innerHTML = this.marked.parse(this.elNodeContent.value)
}// }}}
takeFocus() {// {{{
this.elNodeContent.focus()
@ -45,6 +77,28 @@ export class N2NodeUI extends CustomHTMLElement {
isModified() {// {{{
return this.node?.isModified()
}// }}}
showMarkdown(state) {// {{{
switch (state) {
case true:
this.elNodeMarkdown.innerHTML = this.marked.parse(this.elNodeContent.value)
this.elIconMarkdown.src = `/images/${_VERSION}/icon_markdown.svg`
this.classList.add('show-markdown')
break
case false:
this.elIconMarkdown.src = `/images/${_VERSION}/icon_markdown_hollow.svg`
this.classList.remove('show-markdown')
break
case null:
case undefined:
return this.classList.contains('show-markdown')
}
}// }}}
editMarkdown(data) {// {{{
this.showMarkdown(false)
this.elNodeContent.selectionStart = data.position.start
this.elNodeContent.selectionEnd = data.position.end
this.elNodeContent.focus()
}// }}}
}
customElements.define('n2-nodeui', N2NodeUI)
@ -174,14 +228,6 @@ export class Node {
this._content = new_content
this._modified = true
_mbus.dispatch('NODE_MODIFIED')
/* TODO - implement crypto
if (this.CryptoKeyID == 0)
// Logic behind plaintext not being decrypted is that
// only encrypted values can be in a decrypted state.
this._decrypted = false
else
this._decrypted = true
*/
}//}}}
async save() {//{{{
this.data.Content = this._content