Compare commits
2 commits
e276e6d156
...
26fe670965
Author | SHA1 | Date | |
---|---|---|---|
|
26fe670965 | ||
|
bb6279c55a |
4 changed files with 100 additions and 35 deletions
|
@ -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;
|
||||
|
|
|
@ -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() {//{{{
|
||||
|
|
|
@ -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>
|
||||
<${NodeUI} app=${this} ref=${this.nodeUI} startNode=${startNode} />
|
||||
`
|
||||
}//}}}
|
||||
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) {//{{{
|
||||
// Creating a default value if it doesn't exist already.
|
||||
this.getNodeExpanded(UUID)
|
||||
this.expandedNodes[UUID].value = 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
|
||||
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>`
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Add table
Reference in a new issue