Tree expansion handled better

This commit is contained in:
Magnus Åhall 2026-06-03 20:31:23 +02:00
parent bea865dd82
commit a3864d2b55
6 changed files with 143 additions and 90 deletions

View file

@ -10,8 +10,7 @@
*/ */
--colorize: invert(59%) sepia(71%) saturate(3270%) hue-rotate(327deg) brightness(100%) contrast(99%); --colorize: invert(59%) sepia(71%) saturate(3270%) hue-rotate(327deg) brightness(100%) contrast(99%);
--tree-expander: 0px;
--show-tree: 0px;
} }
html { html {
@ -22,35 +21,98 @@ html {
filter: var(--colorize); filter: var(--colorize);
} }
/* ------------------------------------- *
* Default application grid in wide mode *
* ------------------------------------- */
#notes2 { #notes2 {
min-height: 100vh; min-height: 100vh;
display: grid; display: grid;
grid-template-areas: grid-template-areas:
"show-tree tree hum crumbs crumbs ding" "tree-expander tree pad1 crumbs crumbs pad2"
"show-tree tree hum name name ding" "tree-expander tree pad1 name name pad2"
"show-tree tree hum sync functions ding" "tree-expander tree pad1 sync functions pad2"
"show-tree tree hum content content ding" "tree-expander tree pad1 content content pad2"
"show-tree tree hum blank blank ding"
; ;
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: 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 { &.hide-tree {
--show-tree: 32px; --tree-expander: 32px;
#tree { #tree {
border-right: none; border-right: none;
} }
n2-tree { n2-tree {
display: none; display: none;
} }
} }
}
/* ------------------------------- *
* Application grid in narrow mode *
* ------------------------------- */
@media only screen and (max-width: 800px) {
#notes2 {
grid-template-areas:
"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-columns: 100%;
grid-template-rows: 1fr;
#tree {
display: grid;
width: 100%;
}
#main-page,
#show-tree { #show-tree {
grid-area: show-tree; display: none;
}
}
#tree {
display: none;
}
}
}
#tree-expander {
grid-area: tree-expander;
color: #333; color: #333;
font-weight: bold; font-weight: bold;
border-right: 2px solid #ddd; border-right: 2px solid #ddd;
@ -67,75 +129,6 @@ html {
writing-mode: vertical-rl; writing-mode: vertical-rl;
transform: rotate(180deg); transform: rotate(180deg);
} }
}
n2-nodeui {
.el-functions {
width: calc(100% - 32px);
}
.el-node-markdown {
overflow-wrap: anywhere;
width: calc(100% - 32px);
}
}
}
@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"
;
grid-template-columns: 32px 16px 1fr 16px;
&.show-tree {
grid-template-areas:
"tree"
;
grid-template-columns: 100%;
grid-template-rows:
1fr;
#tree {
display: grid;
width: 100%;
}
#main-page, #show-tree {
display: none;
}
}
#tree {
display: none;
}
n2-syncprogress {
.el-count {
top: 4px;
}
}
n2-nodeui {
.el-functions {
width: calc(100% - 32px);
}
.el-node-markdown {
overflow-wrap: anywhere;
width: calc(100% - 32px);
}
}
}
} }
#tree { #tree {
@ -181,10 +174,8 @@ html {
&:focus-within { &:focus-within {
n2-tree {} n2-tree {}
} }
.node { .node {
display: grid; display: grid;
grid-template-columns: 40px min-content; grid-template-columns: 40px min-content;
@ -233,6 +224,9 @@ html {
} }
} }
n2-nodeui {
}
[id^="page-"] { [id^="page-"] {
display: none; display: none;
} }
@ -403,6 +397,7 @@ n2-nodeui {
.el-functions { .el-functions {
grid-area: functions; grid-area: functions;
width: calc(100% - 32px);
} }
.el-node-content { .el-node-content {
@ -438,6 +433,9 @@ n2-nodeui {
border-top: 1px solid #e0e0e0; border-top: 1px solid #e0e0e0;
border-bottom: 1px solid #e0e0e0; border-bottom: 1px solid #e0e0e0;
margin-bottom: 32px; margin-bottom: 32px;
overflow-wrap: anywhere;
width: calc(100% - 32px);
} }
&.show-markdown { &.show-markdown {

View file

@ -35,7 +35,7 @@
inkscape:window-width="1916" inkscape:window-width="1916"
inkscape:window-height="1161" inkscape:window-height="1161"
inkscape:window-x="0" inkscape:window-x="0"
inkscape:window-y="18" inkscape:window-y="0"
inkscape:window-maximized="1" inkscape:window-maximized="1"
inkscape:showpageshadow="true" inkscape:showpageshadow="true"
inkscape:pagecheckerboard="0" inkscape:pagecheckerboard="0"
@ -62,6 +62,6 @@
<path <path
d="m 78.736803,96.575592 a 40.634474,40.634474 0 0 1 40.634477,40.634438 c 0,10.06486 -3.68838,19.31694 -9.75227,26.44372 l 1.68795,1.68701 h 4.93863 l 31.2573,31.25736 -9.37719,9.37731 -31.25729,-31.25737 v -4.93863 l -1.68795,-1.68701 c -7.126666,6.06378 -16.378815,9.75204 -26.443681,9.75204 A 40.634474,40.634474 0 0 1 38.102322,137.21003 40.634474,40.634474 0 0 1 78.736803,96.575592 m 0,12.502758 c -15.628636,0 -28.131559,12.50299 -28.131559,28.13168 0,15.62868 12.502923,28.13144 28.131559,28.13144 15.628635,0 28.131557,-12.50276 28.131557,-28.13144 0,-15.62869 -12.502922,-28.13168 -28.131557,-28.13168 z" d="m 78.736803,96.575592 a 40.634474,40.634474 0 0 1 40.634477,40.634438 c 0,10.06486 -3.68838,19.31694 -9.75227,26.44372 l 1.68795,1.68701 h 4.93863 l 31.2573,31.25736 -9.37719,9.37731 -31.25729,-31.25737 v -4.93863 l -1.68795,-1.68701 c -7.126666,6.06378 -16.378815,9.75204 -26.443681,9.75204 A 40.634474,40.634474 0 0 1 38.102322,137.21003 40.634474,40.634474 0 0 1 78.736803,96.575592 m 0,12.502758 c -15.628636,0 -28.131559,12.50299 -28.131559,28.13168 0,15.62868 12.502923,28.13144 28.131559,28.13144 15.628635,0 28.131557,-12.50276 28.131557,-28.13144 0,-15.62869 -12.502922,-28.13168 -28.131557,-28.13168 z"
id="path1" id="path1"
style="stroke-width:6.25145;fill:#fe5f55;fill-opacity:1" /> style="stroke-width:6.25145;fill:#000000;fill-opacity:1" />
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Before After
Before After

View file

@ -206,6 +206,7 @@ export class App {
_mbus.dispatch('CRUMBS_SET', ancestors, () => this.crumbsElement.replaceChildren(this.crumbs.render())) _mbus.dispatch('CRUMBS_SET', ancestors, () => this.crumbsElement.replaceChildren(this.crumbs.render()))
_mbus.dispatch('NODE_UI_OPEN', node) _mbus.dispatch('NODE_UI_OPEN', node)
_mbus.dispatch('NODE_UNMODIFIED') _mbus.dispatch('NODE_UNMODIFIED')
_mbus.dispatch('TREE_EXPANSION', { expand: false, when: 'narrow' })
// Scrolls node into view. // Scrolls node into view.
this.tree.makeVisible(node) this.tree.makeVisible(node)

View file

@ -2,6 +2,62 @@ import { ROOT_NODE } from 'node_store'
import { CustomHTMLElement } from './lib/custom_html_element.mjs' import { CustomHTMLElement } from './lib/custom_html_element.mjs'
import { Color, Solver } from './lib/css_colorize.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 { export class N2Tree extends CustomHTMLElement {
static {// {{{ static {// {{{
this.tmpl = document.createElement('template') this.tmpl = document.createElement('template')
@ -22,7 +78,7 @@ export class N2Tree extends CustomHTMLElement {
</div> </div>
<div class="icons"> <div class="icons">
<img data-el="sync" class='sync colorize' src="/images/${_VERSION}/icon_refresh.svg" /> <img data-el="sync" class='sync colorize' src="/images/${_VERSION}/icon_refresh.svg" />
<img data-el="search" class='search' src="/images/${_VERSION}/icon_search.svg" style="height: 22px" /> <img data-el="search" class='search colorize' src="/images/${_VERSION}/icon_search.svg" style="height: 22px" />
<img data-el="settings" class='settings colorize' src="/images/${_VERSION}/icon_settings.svg" /> <img data-el="settings" class='settings colorize' src="/images/${_VERSION}/icon_settings.svg" />
</div> </div>
<div data-el="treenodes"></div> <div data-el="treenodes"></div>
@ -41,14 +97,15 @@ export class N2Tree extends CustomHTMLElement {
this.selectedNode = null this.selectedNode = null
this.rendered = false this.rendered = false
new TreeExpansionHandler()
this.addEventListener('keydown', event => this.keyHandler(event)) this.addEventListener('keydown', event => this.keyHandler(event))
this.elSearch.addEventListener('click', () => _mbus.dispatch('op-search')) this.elSearch.addEventListener('click', () => _mbus.dispatch('op-search'))
this.elSync.addEventListener('click', () => _sync.run()) this.elSync.addEventListener('click', () => _sync.run())
this.elLogo.addEventListener('click', () => _app.goToNode(ROOT_NODE, false, false)) this.elLogo.addEventListener('click', () => _app.goToNode(ROOT_NODE, false, false))
this.elHideTree.addEventListener('click', event=>{ this.elHideTree.addEventListener('click', event => {
event.stopPropagation() event.stopPropagation()
document.getElementById('notes2').classList.add('hide-tree') _mbus.dispatch('TREE_EXPANSION', { expand: false })
document.getElementById('notes2').classList.remove('show-tree')
}) })
_mbus.subscribe('NODE_MODIFIED', ({ detail }) => { _mbus.subscribe('NODE_MODIFIED', ({ detail }) => {

View file

@ -10,12 +10,17 @@ const CACHED_ASSETS = [
'/images/{{ .VERSION }}/collapsed.svg', '/images/{{ .VERSION }}/collapsed.svg',
'/images/{{ .VERSION }}/expanded.svg', '/images/{{ .VERSION }}/expanded.svg',
'/images/{{ .VERSION }}/icon_history.svg',
'/images/{{ .VERSION }}/icon_markdown_hollow.svg', '/images/{{ .VERSION }}/icon_markdown_hollow.svg',
'/images/{{ .VERSION }}/icon_markdown.svg', '/images/{{ .VERSION }}/icon_markdown.svg',
'/images/{{ .VERSION }}/icon_refresh.svg', '/images/{{ .VERSION }}/icon_refresh.svg',
'/images/{{ .VERSION }}/icon_save_disabled.svg', '/images/{{ .VERSION }}/icon_save_disabled.svg',
'/images/{{ .VERSION }}/icon_save.svg',
'/images/{{ .VERSION }}/icon_search.svg', '/images/{{ .VERSION }}/icon_search.svg',
'/images/{{ .VERSION }}/icon_settings.svg',
'/images/{{ .VERSION }}/icon_table.svg',
'/images/{{ .VERSION }}/leaf.svg', '/images/{{ .VERSION }}/leaf.svg',
'/images/{{ .VERSION }}/logo_small.svg',
'/images/{{ .VERSION }}/logo.svg', '/images/{{ .VERSION }}/logo.svg',
'/js/{{ .VERSION }}/api.mjs', '/js/{{ .VERSION }}/api.mjs',
@ -24,7 +29,7 @@ const CACHED_ASSETS = [
'/js/{{ .VERSION }}/crypto.mjs', '/js/{{ .VERSION }}/crypto.mjs',
'/js/{{ .VERSION }}/file.mjs', '/js/{{ .VERSION }}/file.mjs',
'/js/{{ .VERSION }}/key.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/custom_html_element.mjs',
'/js/{{ .VERSION }}/lib/node_modules/marked/lib/marked.esm.js', '/js/{{ .VERSION }}/lib/node_modules/marked/lib/marked.esm.js',
'/js/{{ .VERSION }}/lib/node_modules/marked-token-position/lib/index.esm.js', '/js/{{ .VERSION }}/lib/node_modules/marked-token-position/lib/index.esm.js',

View file

@ -1,14 +1,6 @@
{{ define "page" }} {{ define "page" }}
<script>
function showTree() {
const notes2 = document.getElementById('notes2')
notes2.classList.remove('hide-tree')
notes2.classList.add('show-tree')
}
</script>
<div id="notes2"> <div id="notes2">
<div id="show-tree" onclick="showTree()">&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>
<div id="main-page"> <div id="main-page">