diff --git a/static/css/notes2.css b/static/css/notes2.css index f7051f3..28ee7a2 100644 --- a/static/css/notes2.css +++ b/static/css/notes2.css @@ -21,7 +21,8 @@ html { } button { - font-size: 1e m; + font-size: 1em; + padding: 4px 8px; } /* ------------------------------------- * @@ -546,7 +547,7 @@ n2-pagehistory { padding: 32px; margin-bottom: 32px; border-radius: 8px; - background-color: #f8f8f8; + background-color: #fafafa; box-shadow: rgba(0, 0, 0, 0.4) 0px 2px 4px, @@ -585,62 +586,72 @@ n2-pagehistory { gap: 1px; border: 1px solid var(--line-color); - &>div>div { + n2-pagehistorynode>* { padding: 8px 12px; background-color: #fff; white-space: nowrap; + } - &.index { + n2-pagehistorynode { + + &.selected .el-index:after { + position: absolute; + left: -20px; + + content: '>'; + color: var(--color1); + font-weight: bold; + margin-right: 8px; + } + + .el-index { + position: relative; text-align: right; } - &.updated { + .el-updated { white-space: initial; } - .date { + .el-date { white-space: nowrap; font-weight: bold; } - .time { + .el-time { white-space: nowrap; color: #555; } - &.name { + .el-name { white-space: initial; /*overflow-wrap: anywhere;*/ word-break: break-all; color: var(--color1); - } } - - .history-node { - display: contents; - } - } - - .el-pagination { - grid-column: 1 / -1; - margin-top: 16px; - - display: grid; - grid-template-columns: repeat(3, min-content); - grid-gap: 16px; - align-items: center; - white-space: nowrap; - user-select: none; - - .el-prev, - .el-next { - font-weight: bold; - cursor: pointer; - border: 1px solid #aaa; - background-color: #eee; - padding: 8px 16px; - border-radius: 4px; - } } } + +.el-pagination { + grid-column: 1 / -1; + margin-top: 16px; + + display: grid; + grid-template-columns: repeat(3, min-content); + grid-gap: 16px; + align-items: center; + white-space: nowrap; + user-select: none; + + .el-prev, + .el-next { + font-weight: bold; + cursor: pointer; + border: 1px solid #aaa; + background-color: #eee; + padding: 8px 16px; + border-radius: 4px; + } +} +} diff --git a/static/js/page_history.mjs b/static/js/page_history.mjs index f37cfbb..37404c7 100644 --- a/static/js/page_history.mjs +++ b/static/js/page_history.mjs @@ -1,5 +1,7 @@ import { CustomHTMLElement } from './lib/custom_html_element.mjs' import { Node } from './page_node.mjs' +import { MarkedPosition } from './marked_position.mjs' + export class N2PageHistory extends CustomHTMLElement { static PAGESIZE = 15 @@ -47,11 +49,14 @@ export class N2PageHistory extends CustomHTMLElement {
>
+ +
` }// }}} constructor() {// {{{ super() + this.selectedNode = null this.setAttribute('tabindex', '-1') this.addEventListener('keydown', event => this.keyHandler(event)) @@ -72,6 +77,10 @@ export class N2PageHistory extends CustomHTMLElement { await this.useNode(event.detail.data) this.render() }) + + _mbus.subscribe('HISTORY_NODE_SELECTED', (event) => { + this.selectedNode = event.detail.data.historyNode + }) }// }}} async render(keepFetchHistoryProgress) {// {{{ this.elNodeName.innerText = this.node.get('Name') @@ -88,24 +97,26 @@ export class N2PageHistory extends CustomHTMLElement { let i = 0 let divs = nodes.map(n => { i++ - - const date = n.get('Updated').slice(0, 10) - const time = n.get('Updated').slice(11, 19) - - const div = document.createElement('div') - div.innerHTML = ` -
${1 + this.nodesTotal - (N2PageHistory.PAGESIZE * (this.page - 1) + i)}
-
${date} ${time}
-
${this.formatSize(n.get('Content').length)}
-
${n.get('Name')}
- ` - div.classList.add('history-node') + const index = 1 + this.nodesTotal - (N2PageHistory.PAGESIZE * (this.page - 1) + i) + const div = new N2PageHistoryNode(n, index) + div.render() return div }) this.elNodes.replaceChildren(...divs) if (!keepFetchHistoryProgress) this.elFetchHistoryProgress.innerText = '' + + // Select the first node. + if (!this.selectedNode) { + this.elNodes.firstElementChild?.select() + } + + // Any selected history node is rendered with markdown. + /* + this.marked = new MarkedPosition() + this.elNodeMarkdown.innerHTML = this.marked.parse(this.elNodeContent.value) + */ }// }}} async useNode(node) {// {{{ @@ -124,18 +135,33 @@ export class N2PageHistory extends CustomHTMLElement { case 'ArrowRight': this.nextPage() break + case 'ArrowUp': + const prevNode = this.selectedNode?.previousElementSibling + if (prevNode) + prevNode.select() + break + case 'ArrowDown': + const nextNode = this.selectedNode?.nextElementSibling + if (nextNode) + nextNode.select() + break } }// }}} prevPage() {// {{{ if (this.page == 1) return + + // Selecting a node on another page is wrong. + this.selectedNode = null this.page-- this.render() }// }}} nextPage() {// {{{ if (this.page >= this.pages) return + // Selecting a node on another page is wrong. + this.selectedNode = null this.page++ this.render() }// }}} @@ -199,6 +225,61 @@ export class N2PageHistory extends CustomHTMLElement { return json }// }}} +} +customElements.define('n2-pagehistory', N2PageHistory) + + +class N2PageHistoryNode extends CustomHTMLElement { + static {// {{{ + this.tmpl = document.createElement('template') + this.tmpl.innerHTML = ` +
+
+
+
+ ` + }// }}} + constructor(node, index) {// {{{ + super() + + this.node = node + this.index = index + + this.style.display = 'contents' + this.selected = false + + this.addEventListener('click', () => this.select()) + + // Another history node has been selected. + _mbus.subscribe('HISTORY_NODE_SELECTED', (event) => { + if (this.node.get('Updated') == event.detail.data.historyNode.node.get('Updated')) + return + this.selected = false + this.render() + }) + }// }}} + + select() {// {{{ + this.selected = true + // Other nodes are told to unselect and rerender. + _mbus.dispatch('HISTORY_NODE_SELECTED', { historyNode: this }) + this.render() + }// }}} + render() {// {{{ + const date = this.node.get('Updated').slice(0, 10) + const time = this.node.get('Updated').slice(11, 19) + + if (this.selected) + this.classList.add('selected') + else + this.classList.remove('selected') + + this.elIndex.innerText = this.index + this.elDate.innerText = date + this.elTime.innerText = time + this.elSize.innerText = this.node.get('Content').length + this.elName.innerText = this.node.get('Name') + }// }}} formatSize(s) {// {{{ let div = 1 let unit = 'B' @@ -215,4 +296,4 @@ export class N2PageHistory extends CustomHTMLElement { }).format(Math.round(s / div)) + ' ' + unit }// }}} } -customElements.define('n2-pagehistory', N2PageHistory) +customElements.define('n2-pagehistorynode', N2PageHistoryNode)