Working node menu

This commit is contained in:
Magnus Åhall 2026-06-16 08:27:01 +02:00
parent 15bd742ef7
commit e71516fd76
3 changed files with 98 additions and 31 deletions

View file

@ -9,7 +9,10 @@
--line-color: #ccc; --line-color: #ccc;
--tree-expander: 0px; --tree-expander: 0px;
--functions-width: 216px; --functions-width: 150px;
--menu-color: #fff;
--menu-item-hover-color: #f4f4f4;
} }
html { html {

View file

@ -2,14 +2,70 @@ import { ROOT_NODE, uuidv7 } from 'node_store'
import { CustomHTMLElement } from './lib/custom_html_element.mjs' import { CustomHTMLElement } from './lib/custom_html_element.mjs'
import { MarkedPosition } from './marked_position.mjs' import { MarkedPosition } from './marked_position.mjs'
class N2NodeMenu extends CustomHTMLElement {
static {// {{{
this.tmpl = document.createElement('template')
this.tmpl.innerHTML = `
<style>
n2-nodemenu {
margin: 8px 0;
padding: 0;
position-anchor: --node-menu;
box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px, rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;
top: anchor(bottom);
right: anchor(right);
left: auto;
white-space: nowrap;
.menu-item {
padding: 8px 16px 8px 8px;
border-bottom: 1px solid var(--line-color);
display: grid;
grid-template-columns: min-content 1fr;
grid-gap: 16px;
align-items: center;
&:last-child {
border-bottom: unset;
}
&:hover {
background-color: var(--menu-item-hover-color);
}
}
}
</style>
<div class="node-menu">
<div class="menu-item" data-el="format-tables">
<img class="colorize" src="/images/${_VERSION}/icon_table.svg">
<div>Format tables</div>
</div>
<div class="menu-item" data-el="history">
<img class="colorize" src="/images/${_VERSION}/icon_history.svg">
<div>History</div>
</div>
</div>
`
}// }}}
constructor() {// {{{
super()
}// }}}
}
customElements.define('n2-nodemenu', N2NodeMenu)
export class N2PageNodeUI extends CustomHTMLElement { export class N2PageNodeUI extends CustomHTMLElement {
static {// {{{ static {// {{{
this.tmpl = document.createElement('template') this.tmpl = document.createElement('template')
this.tmpl.innerHTML = ` this.tmpl.innerHTML = `
<style> <style>
.el-functions { n2-nodeui > .el-functions {
display: grid; display: grid;
grid-template-columns: 1fr repeat(5, min-content); grid-template-columns: 1fr repeat(3, min-content);
grid-gap: 8px; grid-gap: 8px;
align-items: center; align-items: center;
justify-items: end; justify-items: end;
@ -18,6 +74,14 @@ export class N2PageNodeUI extends CustomHTMLElement {
img { img {
height: 24px; height: 24px;
} }
.el-menu {
anchor-name: --node-menu;
border: 0;
padding: 0;
background-color: unset;
}
} }
</style> </style>
<div data-el="name"></div> <div data-el="name"></div>
@ -28,11 +92,13 @@ export class N2PageNodeUI extends CustomHTMLElement {
<div data-el="functions"> <div data-el="functions">
<img data-el="icon-save" src="/images/${_VERSION}/icon_save_disabled.svg"> <img data-el="icon-save" src="/images/${_VERSION}/icon_save_disabled.svg">
<img data-el="icon-markdown"> <img data-el="icon-markdown">
<img data-el="icon-table-format" class="colorize" src="/images/${_VERSION}/icon_table.svg">
<img data-el="icon-history" class="colorize" src="/images/${_VERSION}/icon_history.svg">
<img data-el="icon-new-document" class="colorize" src="/images/${_VERSION}/icon_new_document.svg"> <img data-el="icon-new-document" class="colorize" src="/images/${_VERSION}/icon_new_document.svg">
<img data-el="icon-menu" class="colorize" src="/images/${_VERSION}/icon_menu.svg" popovertarget="node-menu"> <button data-el="menu" popovertarget="node-functions-menu">
<img data-el="icon-menu" class="colorize" src="/images/${_VERSION}/icon_menu.svg">
</button>
<n2-nodemenu data-el="node-menu" id="node-functions-menu" popover></n2-nodemenu>
</div> </div>
` `
}// }}} }// }}}
@ -41,7 +107,6 @@ export class N2PageNodeUI extends CustomHTMLElement {
this.node = null this.node = null
this.style.display = 'contents' this.style.display = 'contents'
this.classList.add('show-markdown') // TODO Should probably be moved to settings.
this.marked = new MarkedPosition() this.marked = new MarkedPosition()
_mbus.subscribe('NODE_UI_OPEN', event => { _mbus.subscribe('NODE_UI_OPEN', event => {
@ -70,11 +135,27 @@ export class N2PageNodeUI extends CustomHTMLElement {
_mbus.subscribe('MARKDOWN_EDIT', ({ detail }) => this.editMarkdown(detail.data)) _mbus.subscribe('MARKDOWN_EDIT', ({ detail }) => this.editMarkdown(detail.data))
_mbus.subscribe('MARKDOWN_CHANGE_CHECKBOX', ({ detail }) => this.checkboxUpdated(detail.data)) _mbus.subscribe('MARKDOWN_CHANGE_CHECKBOX', ({ detail }) => this.checkboxUpdated(detail.data))
// Binding the node rename handler.
this.elName.addEventListener('click', async () => this.renameNode()) this.elName.addEventListener('click', async () => this.renameNode())
// Bind handlers for content keyboard input and paste.
this.elNodeContent.addEventListener('input', event => this.contentChanged(event)) this.elNodeContent.addEventListener('input', event => this.contentChanged(event))
this.elNodeContent.addEventListener('paste', async (event) => this.pasteHandler(event)) this.elNodeContent.addEventListener('paste', async (event) => this.pasteHandler(event))
// Bind node icon handlers.
this.elIconSave.addEventListener('click', () => this.saveNode())
this.elIconMarkdown.addEventListener('click', () => this.showMarkdown(!this.showMarkdown())) this.elIconMarkdown.addEventListener('click', () => this.showMarkdown(!this.showMarkdown()))
this.elIconTableFormat.addEventListener('click', event => { this.elIconNewDocument.addEventListener('click', event => {
if (event.shiftKey)
_app.createNode(this.node.ParentUUID)
else
_app.createNode()
})
// Bind node menu items to handlers.
this.elNodeMenu.elFormatTables.addEventListener('click', event => {
this.elNodeMenu.hidePopover()
if (!event.shiftKey) if (!event.shiftKey)
this.elNodeContent.value = this.formatAllTables(this.elNodeContent.value) this.elNodeContent.value = this.formatAllTables(this.elNodeContent.value)
else { else {
@ -88,15 +169,12 @@ export class N2PageNodeUI extends CustomHTMLElement {
this.node.setContent(this.elNodeContent.value) this.node.setContent(this.elNodeContent.value)
}) })
this.elIconHistory.addEventListener('click', () => _mbus.dispatch('SHOW_PAGE', { page: 'history' })) this.elNodeMenu.elHistory.addEventListener('click', () => {
this.elIconSave.addEventListener('click', () => this.saveNode()) _mbus.dispatch('SHOW_PAGE', { page: 'history' })
this.elIconNewDocument.addEventListener('click', event => {
if (event.shiftKey)
_app.createNode(this.node.ParentUUID)
else
_app.createNode()
}) })
// Default is to always show markdown.
this.classList.add('show-markdown') // TODO Should probably be moved to settings.
this.showMarkdown(true) this.showMarkdown(true)
}// }}} }// }}}
renderName() {// {{{ renderName() {// {{{
@ -309,7 +387,7 @@ export class N2PageNodeUI extends CustomHTMLElement {
// Node is modified with the new value. User has to save manually, otherwise other changes could be saved // Node is modified with the new value. User has to save manually, otherwise other changes could be saved
// when a save wasn't expected. // when a save wasn't expected.
const newValue =`[${checkbox.checked ? 'x' : ' '}] ` const newValue = `[${checkbox.checked ? 'x' : ' '}] `
const modifiedContent = this.node.content().slice(0, pos.start) + newValue + this.node.content().slice(pos.end) const modifiedContent = this.node.content().slice(0, pos.start) + newValue + this.node.content().slice(pos.end)
this.node.setContent(modifiedContent) this.node.setContent(modifiedContent)
@ -511,17 +589,5 @@ export class Node {
}//}}} }//}}}
} }
class N2Menu extends CustomHTMLElement {
static {// {{{
this.tmpl = document.createElement('template')
this.tmpl.innerHTML = `
<div id="node-menu" popover>Popover content</div>
`
}// }}}
constructor() {// {{{
super()
}// }}}
}
customElements.define('n2-menu', N2Menu)
// vim: foldmethod=marker // vim: foldmethod=marker

View file

@ -6,8 +6,6 @@
<div id="notes2" class="page-history"> <div id="notes2" class="page-history">
<div id="tree-expander" onclick="window._mbus.dispatch('TREE_EXPANSION', { expand: true })">&gt;</div> <div id="tree-expander" onclick="window._mbus.dispatch('TREE_EXPANSION', { expand: true })">&gt;</div>
<div id="tree" tabindex=0></div> <div id="tree" tabindex=0></div>
<n2-menu></n2-menu>
<div id="node-menu" popover>Popover content</div>
<div id="main-page"> <div id="main-page">
<!-- Storage stats --> <!-- Storage stats -->