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;
|
display: grid;
|
||||||
grid-template-areas: "tree crumbs" "tree sync" "tree name" "tree content" "tree blank";
|
grid-template-areas: "tree crumbs" "tree sync" "tree name" "tree content" "tree blank";
|
||||||
grid-template-columns: min-content 1fr;
|
grid-template-columns: min-content 1fr;
|
||||||
|
grid-template-rows: 64px 56px 48px min-content 1fr;
|
||||||
}
|
}
|
||||||
@media only screen and (max-width: 600px) {
|
@media only screen and (max-width: 600px) {
|
||||||
#notes2 {
|
#notes2 {
|
||||||
|
@ -77,6 +78,7 @@ html {
|
||||||
#crumbs {
|
#crumbs {
|
||||||
grid-area: crumbs;
|
grid-area: crumbs;
|
||||||
display: grid;
|
display: grid;
|
||||||
|
align-items: center;
|
||||||
justify-items: center;
|
justify-items: center;
|
||||||
margin: 16px;
|
margin: 16px;
|
||||||
}
|
}
|
||||||
|
@ -84,19 +86,14 @@ html {
|
||||||
grid-area: sync;
|
grid-area: sync;
|
||||||
display: grid;
|
display: grid;
|
||||||
justify-items: center;
|
justify-items: center;
|
||||||
justify-self: center;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 900px;
|
|
||||||
height: 56px;
|
height: 56px;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
#sync-progress.hidden {
|
|
||||||
visibility: hidden;
|
|
||||||
opacity: 0;
|
|
||||||
transition: visibility 0s 500ms, opacity 500ms linear;
|
|
||||||
}
|
|
||||||
#sync-progress progress {
|
#sync-progress progress {
|
||||||
width: calc(100% - 16px);
|
width: 100%;
|
||||||
|
padding: 0 7px;
|
||||||
|
max-width: 900px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
@ -121,11 +118,18 @@ html {
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
#sync-progress .count {
|
#sync-progress .count {
|
||||||
|
width: min-content;
|
||||||
|
white-space: nowrap;
|
||||||
margin-top: 0px;
|
margin-top: 0px;
|
||||||
color: #888;
|
color: #888;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 22px;
|
top: 22px;
|
||||||
}
|
}
|
||||||
|
#sync-progress.hidden {
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
transition: visibility 0s 500ms, opacity 500ms linear;
|
||||||
|
}
|
||||||
.crumbs {
|
.crumbs {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|
|
@ -385,9 +385,7 @@ export class Node {
|
||||||
if (this._children_fetched)
|
if (this._children_fetched)
|
||||||
return this.Children
|
return this.Children
|
||||||
|
|
||||||
|
|
||||||
this.Children = await nodeStore.getTreeNodes(this.UUID, this.Level + 1)
|
this.Children = await nodeStore.getTreeNodes(this.UUID, this.Level + 1)
|
||||||
|
|
||||||
this._children_fetched = true
|
this._children_fetched = true
|
||||||
|
|
||||||
// Children are sorted to allow for storing siblings befare and after.
|
// Children are sorted to allow for storing siblings befare and after.
|
||||||
|
@ -403,6 +401,9 @@ export class Node {
|
||||||
this.Children[i]._parent = this
|
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
|
return this.Children
|
||||||
}//}}}
|
}//}}}
|
||||||
hasChildren() {//{{{
|
hasChildren() {//{{{
|
||||||
|
|
|
@ -29,10 +29,7 @@ export class Notes2 extends Component {
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<${Tree} app=${this} key=${treeKey} startNode=${startNode} />
|
<${Tree} app=${this} key=${treeKey} startNode=${startNode} />
|
||||||
|
<${NodeUI} app=${this} ref=${this.nodeUI} startNode=${startNode} />
|
||||||
<div id="nodeui">
|
|
||||||
<${NodeUI} app=${this} ref=${this.nodeUI} startNode=${startNode} />
|
|
||||||
</div>
|
|
||||||
`
|
`
|
||||||
}//}}}
|
}//}}}
|
||||||
getStartNode() {//{{{
|
getStartNode() {//{{{
|
||||||
|
@ -84,6 +81,11 @@ class Tree extends Component {
|
||||||
this.expandedNodes = {} // keyed on UUID
|
this.expandedNodes = {} // keyed on UUID
|
||||||
this.treeDiv = createRef()
|
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.props.app.tree = this
|
||||||
|
|
||||||
this.populateFirstLevel()
|
this.populateFirstLevel()
|
||||||
|
@ -113,6 +115,20 @@ class Tree extends Component {
|
||||||
this.setSelected(node)
|
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) {//{{{
|
populateFirstLevel(callback = null) {//{{{
|
||||||
nodeStore.get(ROOT_NODE)
|
nodeStore.get(ROOT_NODE)
|
||||||
.then(node => node.fetchChildren())
|
.then(node => node.fetchChildren())
|
||||||
|
@ -145,7 +161,7 @@ class Tree extends Component {
|
||||||
this.treeNodeComponents[node.UUID]?.current.forceUpdate()
|
this.treeNodeComponents[node.UUID]?.current.forceUpdate()
|
||||||
|
|
||||||
if (!dontExpand)
|
if (!dontExpand)
|
||||||
this.setNodeExpanded(node.UUID, true)
|
this.setNodeExpanded(node, true)
|
||||||
}//}}}
|
}//}}}
|
||||||
isSelected(node) {//{{{
|
isSelected(node) {//{{{
|
||||||
return this.selectedNode?.UUID === node.UUID
|
return this.selectedNode?.UUID === node.UUID
|
||||||
|
@ -155,7 +171,7 @@ class Tree extends Component {
|
||||||
const ancestry = await nodeStore.getNodeAncestry(node, [])
|
const ancestry = await nodeStore.getNodeAncestry(node, [])
|
||||||
for (const i in ancestry) {
|
for (const i in ancestry) {
|
||||||
await nodeStore.node(ancestry[i].UUID).fetchChildren()
|
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.
|
// Already a top node, no need to expand anything.
|
||||||
|
@ -163,17 +179,29 @@ class Tree extends Component {
|
||||||
return
|
return
|
||||||
|
|
||||||
// Start the chain of by expanding the top node.
|
// 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) {//{{{
|
getNodeExpanded(UUID) {//{{{
|
||||||
if (this.expandedNodes[UUID] === undefined)
|
if (this.expandedNodes[UUID] === undefined)
|
||||||
this.expandedNodes[UUID] = signal(false)
|
this.expandedNodes[UUID] = signal(false)
|
||||||
return this.expandedNodes[UUID].value
|
return this.expandedNodes[UUID].value
|
||||||
}//}}}
|
}//}}}
|
||||||
setNodeExpanded(UUID, value) {//{{{
|
async setNodeExpanded(node, value) {//{{{
|
||||||
// Creating a default value if it doesn't exist already.
|
return new Promise((resolve, reject) => {
|
||||||
this.getNodeExpanded(UUID)
|
const work = uuid=>{
|
||||||
this.expandedNodes[UUID].value = value
|
// 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) {//{{{
|
getParentWithNextSibling(node) {//{{{
|
||||||
let currNode = node
|
let currNode = node
|
||||||
|
@ -190,17 +218,33 @@ class Tree extends Component {
|
||||||
return currNode
|
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) {//{{{
|
async keyHandler(event) {//{{{
|
||||||
let handled = true
|
let handled = true
|
||||||
const n = this.selectedNode
|
const n = this.selectedNode
|
||||||
const Space = ' '
|
const Space = ' '
|
||||||
|
|
||||||
switch (event.key) {
|
switch (event.key) {
|
||||||
// Space is toggling expansion.
|
// Space and enter is toggling expansion.
|
||||||
|
// Holding shift down does it recursively.
|
||||||
case Space:
|
case Space:
|
||||||
case 'Enter':
|
case 'Enter':
|
||||||
const expanded = this.getNodeExpanded(n.UUID)
|
const expanded = this.getNodeExpanded(n.UUID)
|
||||||
this.setNodeExpanded(n.UUID, !expanded)
|
if (event.shiftKey) {
|
||||||
|
this.recursiveExpand(n, !expanded)
|
||||||
|
} else {
|
||||||
|
this.setNodeExpanded(n, !expanded)
|
||||||
|
}
|
||||||
break
|
break
|
||||||
|
|
||||||
case 'g':
|
case 'g':
|
||||||
|
@ -249,7 +293,7 @@ class Tree extends Component {
|
||||||
|
|
||||||
const expanded = this.getNodeExpanded(n.UUID)
|
const expanded = this.getNodeExpanded(n.UUID)
|
||||||
if (expanded && n.hasChildren()) {
|
if (expanded && n.hasChildren()) {
|
||||||
this.setNodeExpanded(n.UUID, false)
|
this.setNodeExpanded(n, false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,7 +320,7 @@ class Tree extends Component {
|
||||||
const expanded = this.getNodeExpanded(n.UUID)
|
const expanded = this.getNodeExpanded(n.UUID)
|
||||||
|
|
||||||
if (!expanded && n.hasChildren()) {
|
if (!expanded && n.hasChildren()) {
|
||||||
this.setNodeExpanded(n.UUID, true)
|
this.setNodeExpanded(n, true)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -408,7 +452,7 @@ class TreeNode extends Component {
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div class="node">
|
<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="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 class="children ${node.Children.length > 0 && tree.getNodeExpanded(node.UUID) ? 'expanded' : 'collapsed'}">${children}</div>
|
||||||
</div>`
|
</div>`
|
||||||
|
|
|
@ -19,6 +19,13 @@ html {
|
||||||
"tree blank"
|
"tree blank"
|
||||||
;
|
;
|
||||||
grid-template-columns: min-content 1fr;
|
grid-template-columns: min-content 1fr;
|
||||||
|
grid-template-rows:
|
||||||
|
64px
|
||||||
|
56px
|
||||||
|
48px
|
||||||
|
min-content
|
||||||
|
1fr;
|
||||||
|
|
||||||
|
|
||||||
@media only screen and (max-width: 600px) {
|
@media only screen and (max-width: 600px) {
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
|
@ -46,6 +53,10 @@ html {
|
||||||
color: #ddd;
|
color: #ddd;
|
||||||
z-index: 100; // Over crumbs shadow
|
z-index: 100; // Over crumbs shadow
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
//background-color: #f0f;
|
||||||
|
}
|
||||||
|
|
||||||
#logo {
|
#logo {
|
||||||
display: grid;
|
display: grid;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -114,6 +125,7 @@ html {
|
||||||
#crumbs {
|
#crumbs {
|
||||||
grid-area: crumbs;
|
grid-area: crumbs;
|
||||||
display: grid;
|
display: grid;
|
||||||
|
align-items: center;
|
||||||
justify-items: center;
|
justify-items: center;
|
||||||
margin: 16px;
|
margin: 16px;
|
||||||
}
|
}
|
||||||
|
@ -122,20 +134,15 @@ html {
|
||||||
grid-area: sync;
|
grid-area: sync;
|
||||||
display: grid;
|
display: grid;
|
||||||
justify-items: center;
|
justify-items: center;
|
||||||
justify-self: center;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 900px;
|
|
||||||
height: 56px;
|
height: 56px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
&.hidden {
|
|
||||||
visibility: hidden;
|
|
||||||
opacity: 0;
|
|
||||||
transition: visibility 0s 500ms, opacity 500ms linear;
|
|
||||||
}
|
|
||||||
|
|
||||||
progress {
|
progress {
|
||||||
width: calc(100% - 16px);
|
width: 100%;
|
||||||
|
padding: 0 7px;
|
||||||
|
max-width: 900px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
@ -166,11 +173,20 @@ html {
|
||||||
}
|
}
|
||||||
|
|
||||||
.count {
|
.count {
|
||||||
|
width: min-content;
|
||||||
|
white-space: nowrap;
|
||||||
margin-top: 0px;
|
margin-top: 0px;
|
||||||
color: #888;
|
color: #888;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 22px;
|
top: 22px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.hidden {
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
transition: visibility 0s 500ms, opacity 500ms linear;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.crumbs {
|
.crumbs {
|
||||||
|
|
Loading…
Add table
Reference in a new issue