From a3864d2b556ffc96ed4221e8e7265308323f5486 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20=C3=85hall?= Date: Wed, 3 Jun 2026 20:31:23 +0200 Subject: [PATCH] Tree expansion handled better --- static/css/notes2.css | 146 +++++++++++++++++----------------- static/images/icon_search.svg | 4 +- static/js/app.mjs | 1 + static/js/tree.mjs | 65 ++++++++++++++- static/service_worker.js | 7 +- views/pages/notes2.gotmpl | 10 +-- 6 files changed, 143 insertions(+), 90 deletions(-) diff --git a/static/css/notes2.css b/static/css/notes2.css index ad07770..14f475e 100644 --- a/static/css/notes2.css +++ b/static/css/notes2.css @@ -10,8 +10,7 @@ */ --colorize: invert(59%) sepia(71%) saturate(3270%) hue-rotate(327deg) brightness(100%) contrast(99%); - - --show-tree: 0px; + --tree-expander: 0px; } html { @@ -22,95 +21,86 @@ html { filter: var(--colorize); } +/* ------------------------------------- * +* Default application grid in wide mode * +* ------------------------------------- */ #notes2 { min-height: 100vh; display: grid; grid-template-areas: - "show-tree tree hum crumbs crumbs ding" - "show-tree tree hum name name ding" - "show-tree tree hum sync functions ding" - "show-tree tree hum content content ding" - "show-tree tree hum blank blank ding" + "tree-expander tree pad1 crumbs crumbs pad2" + "tree-expander tree pad1 name name pad2" + "tree-expander tree pad1 sync functions pad2" + "tree-expander tree pad1 content content pad2" ; - grid-template-columns: var(--show-tree) min-content minmax(32px, 1fr) minmax(min-content, calc(900px - 156px)) 156px minmax(32px, 1fr); + grid-template-columns: + /* Tree-expander */ + var(--tree-expander) + /* Tree */ + min-content minmax(32px, 1fr) + /* Sync */ + minmax(min-content, calc(900px - 156px)) + /* Functions */ + 156px + /* Content */ + minmax(32px, 1fr); + grid-template-rows: - min-content min-content 48px 1fr; + /* Crumbs */ + min-content + /* Name */ + min-content + /* Sync */ + 48px + /* Content */ + 1fr; + + /* Tree expander is collapsed as default */ + --tree-expander: 0px; &.hide-tree { - --show-tree: 32px; + --tree-expander: 32px; + #tree { border-right: none; } + n2-tree { display: none; } } - - #show-tree { - grid-area: show-tree; - color: #333; - font-weight: bold; - border-right: 2px solid #ddd; - - display: grid; - justify-items: center; - align-items: start; - - padding-top: 8px; - font-size: 1.25em; - - div div { - display: inline-block; - writing-mode: vertical-rl; - transform: rotate(180deg); - } - } - - n2-nodeui { - .el-functions { - width: calc(100% - 32px); - } - - .el-node-markdown { - overflow-wrap: anywhere; - width: calc(100% - 32px); - } - } - - - } +/* ------------------------------- * + * Application grid in narrow mode * + * ------------------------------- */ @media only screen and (max-width: 800px) { #notes2 { grid-template-areas: - "show-tree hum crumbs ding" - "show-tree hum name ding" - "show-tree hum functions ding" - "show-tree hum content ding" - "show-tree hum blank ding" - "show-tree hum sync ding" + "tree-expander pad1 crumbs pad2" + "tree-expander pad1 name pad2" + "tree-expander pad1 functions pad2" + "tree-expander pad1 content pad2" + "tree-expander pad1 blank pad2" + "tree-expander pad1 sync pad2" ; grid-template-columns: 32px 16px 1fr 16px; &.show-tree { - - grid-template-areas: - "tree" - ; + grid-template-areas: "tree"; grid-template-columns: 100%; - grid-template-rows: - 1fr; + grid-template-rows: 1fr; #tree { display: grid; width: 100%; } - - #main-page, #show-tree { + + #main-page, + #show-tree { display: none; } } @@ -118,23 +108,26 @@ html { #tree { display: none; } + } +} - n2-syncprogress { - .el-count { - top: 4px; - } - } +#tree-expander { + grid-area: tree-expander; + color: #333; + font-weight: bold; + border-right: 2px solid #ddd; - n2-nodeui { - .el-functions { - width: calc(100% - 32px); - } + display: grid; + justify-items: center; + align-items: start; - .el-node-markdown { - overflow-wrap: anywhere; - width: calc(100% - 32px); - } - } + padding-top: 8px; + font-size: 1.25em; + + div div { + display: inline-block; + writing-mode: vertical-rl; + transform: rotate(180deg); } } @@ -181,10 +174,8 @@ html { &:focus-within { n2-tree {} - } - .node { display: grid; grid-template-columns: 40px min-content; @@ -233,6 +224,9 @@ html { } } +n2-nodeui { +} + [id^="page-"] { display: none; } @@ -403,6 +397,7 @@ n2-nodeui { .el-functions { grid-area: functions; + width: calc(100% - 32px); } .el-node-content { @@ -438,6 +433,9 @@ n2-nodeui { border-top: 1px solid #e0e0e0; border-bottom: 1px solid #e0e0e0; margin-bottom: 32px; + + overflow-wrap: anywhere; + width: calc(100% - 32px); } &.show-markdown { diff --git a/static/images/icon_search.svg b/static/images/icon_search.svg index 6de83dd..7b05f5c 100644 --- a/static/images/icon_search.svg +++ b/static/images/icon_search.svg @@ -35,7 +35,7 @@ inkscape:window-width="1916" inkscape:window-height="1161" inkscape:window-x="0" - inkscape:window-y="18" + inkscape:window-y="0" inkscape:window-maximized="1" inkscape:showpageshadow="true" inkscape:pagecheckerboard="0" @@ -62,6 +62,6 @@ + style="stroke-width:6.25145;fill:#000000;fill-opacity:1" /> diff --git a/static/js/app.mjs b/static/js/app.mjs index feeec3a..8ff6229 100644 --- a/static/js/app.mjs +++ b/static/js/app.mjs @@ -206,6 +206,7 @@ export class App { _mbus.dispatch('CRUMBS_SET', ancestors, () => this.crumbsElement.replaceChildren(this.crumbs.render())) _mbus.dispatch('NODE_UI_OPEN', node) _mbus.dispatch('NODE_UNMODIFIED') + _mbus.dispatch('TREE_EXPANSION', { expand: false, when: 'narrow' }) // Scrolls node into view. this.tree.makeVisible(node) diff --git a/static/js/tree.mjs b/static/js/tree.mjs index 55a37ee..04555f6 100644 --- a/static/js/tree.mjs +++ b/static/js/tree.mjs @@ -2,6 +2,62 @@ import { ROOT_NODE } from 'node_store' import { CustomHTMLElement } from './lib/custom_html_element.mjs' import { Color, Solver } from './lib/css_colorize.mjs' +// TreeExpandedHandler is responsible for collapsing or expanding +// the node tree, wide view or narrow "mobile" view. +class TreeExpansionHandler {// {{{ + constructor() { + this.isNarrow = false + this.initializeMediaHandler() + this.initializeBusEvents() + } + + initializeBusEvents() { + _mbus.subscribe('TREE_EXPANSION', ({ detail }) => { + // When a node is selected on the screen and the screen + // is narrow the tree is automatically hidden. + // + // Can't always hide the tree automatically when a node + // is selected since the wide mode shows the tree as standard. + if (detail.data?.when == 'narrow' && !this.isNarrow) + return + + this.treeExpansion(detail.data?.expand) + }) + } + + initializeMediaHandler() { + const query = window.matchMedia('(max-width: 800px)') + query.addEventListener('change', event => this.screenNarrowHandler(event)) + + // Run once to set initial state, instead of needing to toggle state. + this.screenNarrowHandler(query) + } + + // When screen becomes narrow, the tree is automatically hidden. + // Primary purpose is to read content, not browse, which is why + // the tree is hidden as standard. + screenNarrowHandler(event) { + this.isNarrow = event.matches + + if (this.isNarrow) + this.treeExpansion(false) + else + this.treeExpansion(true) + } + + treeExpansion(expanded) { + const notes2 = document.getElementById('notes2') + + if (expanded) { + notes2.classList.remove('hide-tree') + notes2.classList.add('show-tree') + } else { + notes2.classList.add('hide-tree') + notes2.classList.remove('show-tree') + } + } +}// }}} + export class N2Tree extends CustomHTMLElement { static {// {{{ this.tmpl = document.createElement('template') @@ -22,7 +78,7 @@ export class N2Tree extends CustomHTMLElement {
- +
@@ -41,14 +97,15 @@ export class N2Tree extends CustomHTMLElement { this.selectedNode = null this.rendered = false + new TreeExpansionHandler() + this.addEventListener('keydown', event => this.keyHandler(event)) this.elSearch.addEventListener('click', () => _mbus.dispatch('op-search')) this.elSync.addEventListener('click', () => _sync.run()) this.elLogo.addEventListener('click', () => _app.goToNode(ROOT_NODE, false, false)) - this.elHideTree.addEventListener('click', event=>{ + this.elHideTree.addEventListener('click', event => { event.stopPropagation() - document.getElementById('notes2').classList.add('hide-tree') - document.getElementById('notes2').classList.remove('show-tree') + _mbus.dispatch('TREE_EXPANSION', { expand: false }) }) _mbus.subscribe('NODE_MODIFIED', ({ detail }) => { diff --git a/static/service_worker.js b/static/service_worker.js index b01d9cc..55a5f09 100644 --- a/static/service_worker.js +++ b/static/service_worker.js @@ -10,12 +10,17 @@ const CACHED_ASSETS = [ '/images/{{ .VERSION }}/collapsed.svg', '/images/{{ .VERSION }}/expanded.svg', + '/images/{{ .VERSION }}/icon_history.svg', '/images/{{ .VERSION }}/icon_markdown_hollow.svg', '/images/{{ .VERSION }}/icon_markdown.svg', '/images/{{ .VERSION }}/icon_refresh.svg', '/images/{{ .VERSION }}/icon_save_disabled.svg', + '/images/{{ .VERSION }}/icon_save.svg', '/images/{{ .VERSION }}/icon_search.svg', + '/images/{{ .VERSION }}/icon_settings.svg', + '/images/{{ .VERSION }}/icon_table.svg', '/images/{{ .VERSION }}/leaf.svg', + '/images/{{ .VERSION }}/logo_small.svg', '/images/{{ .VERSION }}/logo.svg', '/js/{{ .VERSION }}/api.mjs', @@ -24,7 +29,7 @@ const CACHED_ASSETS = [ '/js/{{ .VERSION }}/crypto.mjs', '/js/{{ .VERSION }}/file.mjs', '/js/{{ .VERSION }}/key.mjs', - '/js/{{ .VERSION }}/lib/css_colorize.js', + '/js/{{ .VERSION }}/lib/css_colorize.mjs', '/js/{{ .VERSION }}/lib/custom_html_element.mjs', '/js/{{ .VERSION }}/lib/node_modules/marked/lib/marked.esm.js', '/js/{{ .VERSION }}/lib/node_modules/marked-token-position/lib/index.esm.js', diff --git a/views/pages/notes2.gotmpl b/views/pages/notes2.gotmpl index fe74240..f15bbb5 100644 --- a/views/pages/notes2.gotmpl +++ b/views/pages/notes2.gotmpl @@ -1,14 +1,6 @@ {{ define "page" }} - -
-
>
+
>