Compare commits

...

2 commits

Author SHA1 Message Date
Magnus Åhall
26fe670965 Implemented a notification system for fetched children 2025-02-09 13:49:37 +01:00
Magnus Åhall
bb6279c55a Better grid layout 2025-02-09 11:50:11 +01:00
4 changed files with 100 additions and 35 deletions

View file

@ -6,6 +6,7 @@ html {
display: grid;
grid-template-areas: "tree crumbs" "tree sync" "tree name" "tree content" "tree blank";
grid-template-columns: min-content 1fr;
grid-template-rows: 64px 56px 48px min-content 1fr;
}
@media only screen and (max-width: 600px) {
#notes2 {
@ -77,6 +78,7 @@ html {
#crumbs {
grid-area: crumbs;
display: grid;
align-items: center;
justify-items: center;
margin: 16px;
}
@ -84,19 +86,14 @@ html {
grid-area: sync;
display: grid;
justify-items: center;
justify-self: center;
width: 100%;
max-width: 900px;
height: 56px;
position: relative;
}
#sync-progress.hidden {
visibility: hidden;
opacity: 0;
transition: visibility 0s 500ms, opacity 500ms linear;
}
#sync-progress progress {
width: calc(100% - 16px);
width: 100%;
padding: 0 7px;
max-width: 900px;
height: 16px;
border-radius: 4px;
}
@ -121,11 +118,18 @@ html {
border-radius: 4px;
}
#sync-progress .count {
width: min-content;
white-space: nowrap;
margin-top: 0px;
color: #888;
position: absolute;
top: 22px;
}
#sync-progress.hidden {
visibility: hidden;
opacity: 0;
transition: visibility 0s 500ms, opacity 500ms linear;
}
.crumbs {
display: flex;
flex-wrap: wrap;

View file

@ -385,9 +385,7 @@ export class Node {
if (this._children_fetched)
return this.Children
this.Children = await nodeStore.getTreeNodes(this.UUID, this.Level + 1)
this._children_fetched = true
// Children are sorted to allow for storing siblings befare and after.
@ -403,6 +401,9 @@ export class Node {
this.Children[i]._parent = this
}
// Notify the tree that all children are fetched and ready to process.
_notes2.current.tree.fetchChildrenOn(this.UUID)
return this.Children
}//}}}
hasChildren() {//{{{

View file

@ -29,10 +29,7 @@ export class Notes2 extends Component {
return html`
<${Tree} app=${this} key=${treeKey} startNode=${startNode} />
<div id="nodeui">
<${NodeUI} app=${this} ref=${this.nodeUI} startNode=${startNode} />
</div>
`
}//}}}
getStartNode() {//{{{
@ -84,6 +81,11 @@ class Tree extends Component {
this.expandedNodes = {} // keyed on UUID
this.treeDiv = createRef()
// childrenFetchedCallbacks is keyed on a UUID and each
// item is an array with callbacks called when a UUID has
// had all children fetched.
this.childrenFetchedCallbacks = {}
this.props.app.tree = this
this.populateFirstLevel()
@ -113,6 +115,20 @@ class Tree extends Component {
this.setSelected(node)
}//}}}
fetchChildrenNotify(uuid, fn) {//{{{
if (this.childrenFetchedCallbacks[uuid] === undefined)
this.childrenFetchedCallbacks[uuid] = [fn]
else
this.childrenFetchedCallbacks[uuid].push(fn)
}//}}}
fetchChildrenOn(uuid) {//{{{
if (this.childrenFetchedCallbacks[uuid] === undefined)
return
for (const fn of this.childrenFetchedCallbacks[uuid])
fn(uuid)
delete this.childrenFetchedCallbacks[uuid]
}//}}}
populateFirstLevel(callback = null) {//{{{
nodeStore.get(ROOT_NODE)
.then(node => node.fetchChildren())
@ -145,7 +161,7 @@ class Tree extends Component {
this.treeNodeComponents[node.UUID]?.current.forceUpdate()
if (!dontExpand)
this.setNodeExpanded(node.UUID, true)
this.setNodeExpanded(node, true)
}//}}}
isSelected(node) {//{{{
return this.selectedNode?.UUID === node.UUID
@ -155,7 +171,7 @@ class Tree extends Component {
const ancestry = await nodeStore.getNodeAncestry(node, [])
for (const i in ancestry) {
await nodeStore.node(ancestry[i].UUID).fetchChildren()
this.setNodeExpanded(ancestry[i].UUID, true)
this.setNodeExpanded(ancestry[i], true)
}
// Already a top node, no need to expand anything.
@ -163,17 +179,29 @@ class Tree extends Component {
return
// Start the chain of by expanding the top node.
this.setNodeExpanded(ancestry[ancestry.length - 1].UUID, true)
this.setNodeExpanded(ancestry[ancestry.length - 1], true)
}//}}}
getNodeExpanded(UUID) {//{{{
if (this.expandedNodes[UUID] === undefined)
this.expandedNodes[UUID] = signal(false)
return this.expandedNodes[UUID].value
}//}}}
setNodeExpanded(UUID, value) {//{{{
async setNodeExpanded(node, value) {//{{{
return new Promise((resolve, reject) => {
const work = uuid=>{
// Creating a default value if it doesn't exist already.
this.getNodeExpanded(UUID)
this.expandedNodes[UUID].value = value
this.getNodeExpanded(uuid)
this.expandedNodes[uuid].value = value
resolve()
}
if (node.hasFetchedChildren()) {
work(node.UUID)
return
} else {
this.fetchChildrenNotify(node.UUID, uuid=>work(uuid))
}
})
}//}}}
getParentWithNextSibling(node) {//{{{
let currNode = node
@ -190,17 +218,33 @@ class Tree extends Component {
return currNode
}//}}}
async recursiveExpand(node, state) {//{{{
if (state)
await this.setNodeExpanded(node, true)
for (const child of node.Children)
await this.recursiveExpand(child, state)
if (!state)
await this.setNodeExpanded(node, false)
}//}}}
async keyHandler(event) {//{{{
let handled = true
const n = this.selectedNode
const Space = ' '
switch (event.key) {
// Space is toggling expansion.
// Space and enter is toggling expansion.
// Holding shift down does it recursively.
case Space:
case 'Enter':
const expanded = this.getNodeExpanded(n.UUID)
this.setNodeExpanded(n.UUID, !expanded)
if (event.shiftKey) {
this.recursiveExpand(n, !expanded)
} else {
this.setNodeExpanded(n, !expanded)
}
break
case 'g':
@ -249,7 +293,7 @@ class Tree extends Component {
const expanded = this.getNodeExpanded(n.UUID)
if (expanded && n.hasChildren()) {
this.setNodeExpanded(n.UUID, false)
this.setNodeExpanded(n, false)
return
}
@ -276,7 +320,7 @@ class Tree extends Component {
const expanded = this.getNodeExpanded(n.UUID)
if (!expanded && n.hasChildren()) {
this.setNodeExpanded(n.UUID, true)
this.setNodeExpanded(n, true)
return
}
@ -408,7 +452,7 @@ class TreeNode extends Component {
return html`
<div class="node">
<div class="expand-toggle" onclick=${() => { tree.setNodeExpanded(node.UUID, !tree.getNodeExpanded(node.UUID)) }}>${expandImg}</div>
<div class="expand-toggle" onclick=${() => { tree.setNodeExpanded(node, !tree.getNodeExpanded(node.UUID)) }}>${expandImg}</div>
<div class="name ${selected}" onclick=${() => window._notes2.current.goToNode(node.UUID)}>${node.get('Name')}</div>
<div class="children ${node.Children.length > 0 && tree.getNodeExpanded(node.UUID) ? 'expanded' : 'collapsed'}">${children}</div>
</div>`

View file

@ -19,6 +19,13 @@ html {
"tree blank"
;
grid-template-columns: min-content 1fr;
grid-template-rows:
64px
56px
48px
min-content
1fr;
@media only screen and (max-width: 600px) {
grid-template-areas:
@ -46,6 +53,10 @@ html {
color: #ddd;
z-index: 100; // Over crumbs shadow
&:focus {
//background-color: #f0f;
}
#logo {
display: grid;
position: relative;
@ -114,6 +125,7 @@ html {
#crumbs {
grid-area: crumbs;
display: grid;
align-items: center;
justify-items: center;
margin: 16px;
}
@ -122,20 +134,15 @@ html {
grid-area: sync;
display: grid;
justify-items: center;
justify-self: center;
width: 100%;
max-width: 900px;
height: 56px;
position: relative;
&.hidden {
visibility: hidden;
opacity: 0;
transition: visibility 0s 500ms, opacity 500ms linear;
}
progress {
width: calc(100% - 16px);
width: 100%;
padding: 0 7px;
max-width: 900px;
height: 16px;
border-radius: 4px;
}
@ -166,11 +173,20 @@ html {
}
.count {
width: min-content;
white-space: nowrap;
margin-top: 0px;
color: #888;
position: absolute;
top: 22px;
}
&.hidden {
visibility: hidden;
opacity: 0;
transition: visibility 0s 500ms, opacity 500ms linear;
}
}
.crumbs {