Skip to content

Commit

Permalink
added graph + 'web version' for our app.
Browse files Browse the repository at this point in the history
ilse-langnar committed Aug 1, 2022
1 parent 7ca9da2 commit 6e1ab56
Showing 20 changed files with 449 additions and 417 deletions.
Binary file added docs/feature-graph.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
39 changes: 39 additions & 0 deletions javascript/cli/index.js
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@ const printf = console.log

const envPaths = require('./libs/env-paths.js')
const fs = require('fs')
const path = require('path')
const env_paths = envPaths('ilse', { suffix: "" })
// const inquirer = require("inquirer")

@@ -10,6 +11,8 @@ const env_paths = envPaths('ilse', { suffix: "" })
// const createGraph = require('ngraph.graph')
const readline = require("readline");

var term = require( 'terminal-kit' ).terminal;


// Quine
let target_directories
@@ -171,8 +174,44 @@ class Ilse {

}

tui() {

term.cyan( 'Choose a file:\n' ) ;

let text = fs.readFileSync(`${path.join(target_directories, "notes")}`, "utf8" )
let items = text.split("\n")

term.gridMenu( items , function( error , response ) {

printf( "response -> ", response )
// term( '\n' ).eraseLineAfter.green(
// "#%s selected: %s (%s,%s)\n" ,
// response.selectedIndex ,
// response.selectedText ,
// response.x ,
// response.y
// )

// term( 'a' ).eraseLineAfter.green(
// "#%s selected: %s (%s,%s)\n" ,
// response.selectedIndex ,
// response.selectedText ,
// response.x ,
// response.y
// )

process.exit() ;
})

}

run( brain, payload ) {

if( brain === "ui" ) {
this.tui()
return
}

if( brain === "first" || brain === "f" ) {
printf( "first -> payload -> ", payload )
} else if( brain === "second" || brain === "s" ){
3 changes: 2 additions & 1 deletion javascript/cli/package.json
Original file line number Diff line number Diff line change
@@ -28,6 +28,7 @@
"blessed": "^0.1.81",
"blessed-contrib": "^4.10.1",
"chalk": "^5.0.1",
"env-paths": "^3.0.0"
"env-paths": "^3.0.0",
"terminal-kit": "^2.4.0"
}
}
121 changes: 121 additions & 0 deletions javascript/cli/yarn.lock
Original file line number Diff line number Diff line change
@@ -7,6 +7,18 @@
resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9"
integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==

"@cronvel/get-pixels@^3.4.0":
version "3.4.0"
resolved "https://registry.yarnpkg.com/@cronvel/get-pixels/-/get-pixels-3.4.0.tgz#697cd691c16bbb8b29ed596da73fd6a7e9a2f34d"
integrity sha512-do5jDoX9oCR/dGHE4POVQ3PYDCmQ2Fow4CA72UL4WoE8zUImA/0lChczjfl+ucNjE4sXFWUnzoO6j4WzrUvLnw==
dependencies:
jpeg-js "^0.4.1"
ndarray "^1.0.19"
ndarray-pack "^1.1.1"
node-bitmap "0.0.1"
omggif "^1.0.10"
pngjs "^5.0.0"

abbrev@1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
@@ -115,6 +127,11 @@ charm@~0.1.0:
resolved "https://registry.yarnpkg.com/charm/-/charm-0.1.2.tgz#06c21eed1a1b06aeb67553cdc53e23274bac2296"
integrity sha512-syedaZ9cPe7r3hoQA9twWYKu5AIyCswN5+szkmPBe9ccdLrj4bYaCnLVPTLd2kgVRc7+zoX4tyPgRnFKCj5YjQ==

chroma-js@^2.1.2:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chroma-js/-/chroma-js-2.4.2.tgz#dffc214ed0c11fa8eefca2c36651d8e57cbfb2b0"
integrity sha512-U9eDw6+wt7V8z5NncY2jJfZa+hUH8XEj8FQHgFJTrUFnJfXYf4Ml4adI2vXZOjqRDpFWtYVWypDfZwnJ+HIR4A==

cli-table3@^0.6.1:
version "0.6.2"
resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.2.tgz#aaf5df9d8b5bf12634dc8b3040806a0c07120d2a"
@@ -129,6 +146,13 @@ core-util-is@~1.0.0:
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==

cwise-compiler@^1.1.2:
version "1.1.3"
resolved "https://registry.yarnpkg.com/cwise-compiler/-/cwise-compiler-1.1.3.tgz#f4d667410e850d3a313a7d2db7b1e505bb034cc5"
integrity sha512-WXlK/m+Di8DMMcCjcWr4i+XzcQra9eCdXIJrgh4TUgh0pIS/yJduLxS9JgefsHJ/YVLdgPtXm9r62W92MvanEQ==
dependencies:
uniq "^1.0.0"

drawille-blessed-contrib@>=0.0.1:
version "1.0.0"
resolved "https://registry.yarnpkg.com/drawille-blessed-contrib/-/drawille-blessed-contrib-1.0.0.tgz#15c27934f57a0056ad13596e1561637bc941f0b7"
@@ -199,6 +223,16 @@ inherits@~2.0.1:
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==

iota-array@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/iota-array/-/iota-array-1.0.0.tgz#81ef57fe5d05814cd58c2483632a99c30a0e8087"
integrity sha512-pZ2xT+LOHckCatGQ3DcG/a+QuEqvoxqkiL7tvE8nn3uuu+f6i1TtpB5/FtWFbxUuVr5PZCx8KskuGatbJDXOWA==

is-buffer@^1.0.2:
version "1.1.6"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==

is-fullwidth-code-point@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
@@ -209,6 +243,16 @@ isarray@0.0.1:
resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==

jpeg-js@^0.4.1:
version "0.4.4"
resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.4.tgz#a9f1c6f1f9f0fa80cdb3484ed9635054d28936aa"
integrity sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==

lazyness@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/lazyness/-/lazyness-1.2.0.tgz#5dc0f02c37280436b21f0e4918ce6e72a109c657"
integrity sha512-KenL6EFbwxBwRxG93t0gcUyi0Nw0Ub31FJKN1laA4UscdkL1K1AxUd0gYZdcLU3v+x+wcFi4uQKS5hL+fk500g==

lodash@^4.17.21, lodash@~>=4.17.21:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
@@ -251,6 +295,32 @@ memorystream@^0.3.1:
resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2"
integrity sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==

ndarray-pack@^1.1.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/ndarray-pack/-/ndarray-pack-1.2.1.tgz#8caebeaaa24d5ecf70ff86020637977da8ee585a"
integrity sha512-51cECUJMT0rUZNQa09EoKsnFeDL4x2dHRT0VR5U2H5ZgEcm95ZDWcMA5JShroXjHOejmAD/fg8+H+OvUnVXz2g==
dependencies:
cwise-compiler "^1.1.2"
ndarray "^1.0.13"

ndarray@^1.0.13, ndarray@^1.0.19:
version "1.0.19"
resolved "https://registry.yarnpkg.com/ndarray/-/ndarray-1.0.19.tgz#6785b5f5dfa58b83e31ae5b2a058cfd1ab3f694e"
integrity sha512-B4JHA4vdyZU30ELBw3g7/p9bZupyew5a7tX1Y/gGeF2hafrPaQZhgrGQfsvgfYbgdFZjYwuEcnaobeM/WMW+HQ==
dependencies:
iota-array "^1.0.0"
is-buffer "^1.0.2"

nextgen-events@^1.5.2:
version "1.5.2"
resolved "https://registry.yarnpkg.com/nextgen-events/-/nextgen-events-1.5.2.tgz#72b2b6cbe6912d9be2165188d0169027e65d8ebe"
integrity sha512-0ZEIRQywH5Oxt2IYYufRltQg/KjXhKM7f7MHve+ZIRaKnIR1PPYEXAl2WBmej5Sf0Qh2GgE/21sMRZVuOyxLzw==

node-bitmap@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/node-bitmap/-/node-bitmap-0.0.1.tgz#180eac7003e0c707618ef31368f62f84b2a69091"
integrity sha512-Jx5lPaaLdIaOsj2mVLWMWulXF6GQVdyLvNSxmiYCvZ8Ma2hfKX0POoR2kgKOqz+oFsRreq0yYZjQ2wjE9VNzCA==

node-emoji@^1.11.0:
version "1.11.0"
resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-1.11.0.tgz#69a0150e6946e2f115e9d7ea4df7971e2628301c"
@@ -265,6 +335,11 @@ nopt@~2.1.2:
dependencies:
abbrev "1"

omggif@^1.0.10:
version "1.0.10"
resolved "https://registry.yarnpkg.com/omggif/-/omggif-1.0.10.tgz#ddaaf90d4a42f532e9e7cb3a95ecdd47f17c7b19"
integrity sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw==

optimist@0.2:
version "0.2.8"
resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.2.8.tgz#e981ab7e268b457948593b55674c099a815cac31"
@@ -296,6 +371,11 @@ png-js@~0.1.0:
resolved "https://registry.yarnpkg.com/png-js/-/png-js-0.1.1.tgz#1cc7c212303acabe74263ec3ac78009580242d93"
integrity sha512-NTtk2SyfjBm+xYl2/VZJBhFnTQ4kU5qWC7VC4/iGbrgiU4FuB4xC+74erxADYJIqZICOR1HCvRA7EBHkpjTg9g==

pngjs@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-5.0.0.tgz#e79dd2b215767fd9c04561c01236df960bce7fbb"
integrity sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==

readable-stream@~1.0.2:
version "1.0.34"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c"
@@ -318,6 +398,18 @@ sax@>=0.6.0:
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==

setimmediate@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==

seventh@^0.7.40:
version "0.7.40"
resolved "https://registry.yarnpkg.com/seventh/-/seventh-0.7.40.tgz#a5a010496cb84421bb81f524840484a5aa473be9"
integrity sha512-7sxUydQx4iEh17uJUFjZDAwbffJirldZaNIJvVB/hk9mPEL3J4GpLGSL+mHFH2ydkye46DAsLGqzFJ+/Qj5foQ==
dependencies:
setimmediate "^1.0.5"

sparkline@^0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/sparkline/-/sparkline-0.1.2.tgz#c3bde46252b1354e710c4b200d54816bd9f07a32"
@@ -326,6 +418,11 @@ sparkline@^0.1.1:
here "0.0.2"
nopt "~2.1.2"

string-kit@^0.16.0:
version "0.16.6"
resolved "https://registry.yarnpkg.com/string-kit/-/string-kit-0.16.6.tgz#744d8fa5ace8d5fd53d8e5a9d5fb9b672cf1c83a"
integrity sha512-lPRXwTD+xH9GmHiD8di+iYtLtxO6xcKBDxEa2rCdENHqwuQY40UuFJYyi5CssKTUfzFqQ2fcUufPXaeI5uWAzA==

string-width@^4.2.0:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
@@ -379,11 +476,35 @@ term-canvas@0.0.5:
resolved "https://registry.yarnpkg.com/term-canvas/-/term-canvas-0.0.5.tgz#597afac2fa6369a6f17860bce9c5f66d6ea0ca96"
integrity sha512-eZ3rIWi5yLnKiUcsW8P79fKyooaLmyLWAGqBhFspqMxRNUiB4GmHHk5AzQ4LxvFbJILaXqQZLwbbATLOhCFwkw==

terminal-kit@^2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/terminal-kit/-/terminal-kit-2.4.0.tgz#d572601ee3e25bcf1c05e223990436fce8f1a075"
integrity sha512-lQCKNFYCaVoFM23pcurnQ7wOnsz4u588JNu2sfNOnB8IU6Tl4vdOdHNe7bL2aIiB0kA7m94gS4VI0+3CRI1G/A==
dependencies:
"@cronvel/get-pixels" "^3.4.0"
chroma-js "^2.1.2"
lazyness "^1.2.0"
ndarray "^1.0.19"
nextgen-events "^1.5.2"
seventh "^0.7.40"
string-kit "^0.16.0"
tree-kit "^0.7.4"

tree-kit@^0.7.4:
version "0.7.4"
resolved "https://registry.yarnpkg.com/tree-kit/-/tree-kit-0.7.4.tgz#d6c9dba3e06188952282f196657f6bbbb454a39a"
integrity sha512-Of3tPmVs3b6BhzyUJ7t0olisf47kYr9qAm0XaUpURMjdBn6TwiVaaMuTFoKkkvPGojd9trKAHlrGGcGKcdR1DA==

type-fest@^1.0.2:
version "1.4.0"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.4.0.tgz#e9fb813fe3bf1744ec359d55d1affefa76f14be1"
integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==

uniq@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff"
integrity sha512-Gw+zz50YNKPDKXs+9d+aKAjVwpjNwqzvNpLigIruT4HA9lMZNdMqs9x07kKHB/L9WRzqp4+DlTU5s4wG2esdoA==

"wordwrap@>=0.0.1 <0.1.0", wordwrap@~0.0.2:
version "0.0.3"
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"
2 changes: 2 additions & 0 deletions javascript/web/package.json
Original file line number Diff line number Diff line change
@@ -27,6 +27,8 @@
"clipboardy": "^2.3.0",
"cssprefix": "^2.0.17",
"cytoscape": "^3.20.0",
"cytoscape-dagre": "^2.4.0",
"cytoscape-qtip": "^2.8.0",
"d3-force": "^3.0.0",
"dom-arrow": "^0.0.12",
"draw-line-connect": "^1.2.0",
9 changes: 7 additions & 2 deletions javascript/web/src/App.vue
Original file line number Diff line number Diff line change
@@ -295,16 +295,21 @@ code {
background-color: #D5DADF;
color: var( --secondary-text-color );
background-color: var( --secondary-background-color );
padding: var( --padding );
border-radius: var( --border-radius );
max-height: 400px;
overflow: auto;
margin-left: 50px;
margin-left: 25px;
margin-bottom: 4px;
width: 90%;
box-shadow:0 4px 6px rgba(0,0,0,0.1);
padding: var( --padding );
}
hr {
width: 100%;
border: 1px solid #000;
}
/*========Markdown========*/
.input {
3 changes: 0 additions & 3 deletions javascript/web/src/classes/Config.js
Original file line number Diff line number Diff line change
@@ -55,9 +55,6 @@ export default class Config {
let has_components = ilse.components.length

if( !has_components ) {
let menu = new ilse.classes.Component({ type: "menu", width: 0 })
ilse.components.push( menu )

let daily_notes = new ilse.classes.Component({ type: "daily-notes", width: 12 })
ilse.components.push( daily_notes )
}
91 changes: 48 additions & 43 deletions javascript/web/src/classes/Graph.js
Original file line number Diff line number Diff line change
@@ -44,6 +44,7 @@ export default class Graph {
this.files = await ilse.filesystem.file.get_all.async()
}

/*
// Added files outside of ilse? no problem we scan them here.
async check_for_new_files() {
@@ -65,6 +66,7 @@ export default class Graph {
Messager.emit( "status-line", "set", `Checked ${files_len} for new files` )
}
*/

// If graph exists load it, if not generate it
async initialize_graph() {
@@ -95,7 +97,7 @@ export default class Graph {
this.graph = graph

// BUGFIX: sometimes the user will add files outside of ilse, we should scan those too
this.check_for_new_files()
// this.check_for_new_files()

Messager.emit( "~graph", "loaded", this.graph )

@@ -105,27 +107,18 @@ export default class Graph {
// No Graph
if( !has_graph ) {

// UI, : Set Graph
Messager.emit( "status-line", "set", "Graph not found" )
Messager.emit( "status-line", "set", "Generating Graph" )

// Heavy Operation, generating the graph
// await this.generate()

// Save generated graph to OS-FS
let normalized_graph = to_json( this.graph )
await ilse.filesystem.file.write.async( "graph.json", normalized_graph )

// UI
Messager.emit( "status-line", "set", "Graph Generated" )

// Messaging
// Messager.emit( "~graph", "generated" )
Messager.emit( "~graph", "loaded", this.graph )
}

this.is_loading = false

}

/*
@@ -251,6 +244,7 @@ export default class Graph {


// Get links, tags, yaml from a note's content, then emit so other components can do somethign
/*
get_node_props( content, file ) {
let links = []
@@ -259,7 +253,7 @@ export default class Graph {
let YAML_TOKEN = ilse.config.yaml_token || "---yaml"
if( content.indexOf( "[[" ) !== -1 ) {
links = ilse.utils.extract_tokens_by_delimiters( content, /\[\[.*/, /\]\]/ )
links = ilse.utils.extract_tokens_by_delimiters( content, /\[\[.*\/, /\]\]/ )
Messager.emit( "~graph", "links", { links, file } )
}
@@ -287,7 +281,9 @@ export default class Graph {
return props
}
*/

/*
get_node_props_for_generation( content, file ) {
let links = []
@@ -296,7 +292,7 @@ export default class Graph {
let YAML_TOKEN = ilse.config.yaml_token || "---yaml"
if( content.indexOf( "[[" ) !== -1 ) {
links = ilse.utils.extract_tokens_by_delimiters( content, /\[\[.*/, /\]\]/ )
links = ilse.utils.extract_tokens_by_delimiters( content, /\[\[.\*\/, /\]\]/ )
// Have Links
if( links.length ) {
@@ -326,13 +322,15 @@ export default class Graph {
return props
}
*/

// ilse.graph.files = [ "Javascript.md", "Markdown.md" ], this will update the file as in ilse.graph.files so the current app can search it.o
update_files_file( old_title, new_title ) {
let index = this.files.indexOf( old_title )
this.files.splice( index, 1, new_title )
}
// update_files_file( old_title, new_title ) {
// let index = this.files.indexOf( old_title )
// this.files.splice( index, 1, new_title )
// }

/*
async rename( old_title, new_title ) {
// BUGFIX: sometimes, we want to rename something that we have not yet scanned, thus, we will re-scan them if they don't exist
@@ -366,6 +364,7 @@ export default class Graph {
this.graph.removeNode( old_title )
}
*/

async save( graph ) {

@@ -416,6 +415,7 @@ export default class Graph {

}

/*
rename_links( old_title, new_title ) {
let node = this.graph.getNode( old_title )
@@ -452,7 +452,9 @@ export default class Graph {
return renamed_links
}
*/

/*
// ????
async update_file_on_graph( old_title, new_title ) {
@@ -467,8 +469,10 @@ export default class Graph {
new_node.links = renamed_links
new_node.data = old_node.data
}
*/


/*
// Update backlinks( notes that links to this file )
async update_file_on_filesystem( old_title, new_title ) {
@@ -499,7 +503,9 @@ export default class Graph {
Messager.emit( "status-line", "set", `Updated: ${backlinks.length} links` )
}
*/

/*
async move_file( file, location ) {
// Update it on ilse.graph.graph
@@ -513,52 +519,51 @@ export default class Graph {
// Update on Filesystem
ilse.filesystem.file.rename.async( file, `${location}/${file}` )
}
*/

move_file_to_trash( file ) {
this.move_file( file, `.trash` )
}
// move_file_to_trash( file ) {
// this.move_file( file, `.trash` )
// }

listen() {

Messager.on( "~links", async ( action, payload ) => {
// Messager.on( "~links", async ( action, payload ) => {

if( action === 'new' ) {
this.set_node( payload.link )
}

})
// if( action === 'new' ) {
// this.set_node( payload.link )
// }
// })

Messager.on( "~filesystem", async ( action, payload ) => {
// Messager.on( "~filesystem", async ( action, payload ) => {

if( action === 'loaded' ) {
this.initialize_graph()
}
// if( action === 'loaded' ) {
// this.initialize_graph()
// }

})
// })

Messager.on( "graph", async ( action, payload ) => {

if( action === 'rename-node' ) {

let old_title = payload.old_title
let new_title = payload.new_title

this.rename( old_title, new_title )
// let old_title = payload.old_title
// let new_title = payload.new_title
// this.rename( old_title, new_title )
} else if( action === 'set-node' ) {

this.set_node( payload, this.graph, false )
// this.set_node( payload, this.graph, false )

// Add new file/node to ilse.graph.files
let index = this.files.indexOf( payload )
let has_file_already = index !== -1
if( !has_file_already ) { this.files.push( payload ) }
// // Add new file/node to ilse.graph.files
// let index = this.files.indexOf( payload )
// let has_file_already = index !== -1
// if( !has_file_already ) { this.files.push( payload ) }

} else if( action === 'save' ) {
await this.save( this.graph )
Messager.emit( "status-line", "set", "Saved Graph" )
// await this.save( this.graph )
// Messager.emit( "status-line", "set", "Saved Graph" )
} else if( action === 'move-file-to-trash' ) {
let file = payload.file
this.move_file_to_trash( file )
// let file = payload.file
// this.move_file_to_trash( file )
}

})
5 changes: 0 additions & 5 deletions javascript/web/src/classes/Note.js
Original file line number Diff line number Diff line change
@@ -76,15 +76,10 @@ export default class note {
let is_move_right = number > 0
let note

printf( "this.depth -> ", depth )

if( is_move_right ) {

let spaces = ilse.utils.get_depth_spaces( this.depth + number )
note = `${spaces}${this.id}: ${this.content}`
printf( "note -> ", note )
printf( "this.id -> ", this.id )
printf( "this.id.length -> ", this.id.length )
setTimeout( () => { this.focus() }, 100 )

this.constructor( note )
2 changes: 1 addition & 1 deletion javascript/web/src/components/Component.vue
Original file line number Diff line number Diff line change
@@ -16,8 +16,8 @@
:title="get_title(component)"
)

br
component( v-if="component.get_component()" :is="component.get_component()" :component="component" :style="get_component_margin(component)" )

</template>
<script>
// eslint-disable-next-line
7 changes: 6 additions & 1 deletion javascript/web/src/components/DailyNotes.vue
Original file line number Diff line number Diff line change
@@ -12,7 +12,10 @@
img( src="@/assets/images/x.svg" style="cursor: pointer; width: 17px; margin-left: 5px;" :title="$t('close')" @click="remove(day)" )

.note( v-for="(note, note_index) in day.notes" :key="note_index" :style="get_note_style(note)" )
Note( :note="note" :key="note.id + day.id" @on-enter="on_enter" @on-tab="on_tab" @on-shift-tab="on_shift_tab" @on-link-click="on_note_link_click" @on-esc="on_note_esc" @on-arrow-up="on_note_arrow_up" @on-arrow-down="on_note_arrow_down" @on-note-left-click="on_note_left_click" @on-note-middle-click="on_note_middle_click(note)" @on-note-right-click="on_note_right_click" )

Notes( v-if="note.depth === 0" :note="note" :key="note.id + day.id" @on-enter="on_enter" @on-tab="on_tab" @on-shift-tab="on_shift_tab" @on-link-click="on_note_link_click" @on-esc="on_note_esc" @on-arrow-up="on_note_arrow_up" @on-arrow-down="on_note_arrow_down" @on-note-left-click="on_note_left_click" @on-note-middle-click="on_note_middle_click(note)" @on-note-right-click="on_note_right_click" )

// Note( v-if="note.depth === 0" :note="note" :key="note.id + day.id" @on-enter="on_enter" @on-tab="on_tab" @on-shift-tab="on_shift_tab" @on-link-click="on_note_link_click" @on-esc="on_note_esc" @on-arrow-up="on_note_arrow_up" @on-arrow-down="on_note_arrow_down" @on-note-left-click="on_note_left_click" @on-note-middle-click="on_note_middle_click(note)" @on-note-right-click="on_note_right_click" )
GhostNote( v-if="day.notes.length" @on-enter="on_ghost_note_enter" @on-blur="on_ghost_note_blur" :payload="day" )

@@ -37,6 +40,7 @@ const printf = console.log;
// Components
import Note from "@/components/Note.vue"
import Notes from "@/components/Notes.vue"
import GhostNote from "@/components/GhostNote.vue"
import References from "@/components/References.vue"
@@ -54,6 +58,7 @@ export default {
components: {
Note,
Notes,
GhostNote,
References,
},
21 changes: 20 additions & 1 deletion javascript/web/src/components/File.vue
Original file line number Diff line number Diff line change
@@ -15,6 +15,7 @@
br
br

.loop( v-if="is_on" v-for="( note, index ) of notes" :key="index" :style="get_note_style(note)" )

Notes(
@@ -37,6 +38,8 @@

GhostNote.is-pulled-left( @on-blur="on_ghost_note_blur" @on-enter="on_ghost_note_enter" )

button.button.slick-button.centered( v-if="is_create_file_button_on" style="display: block;" @click="create(file)" ) Create

.space
References( v-if="content && file" :file="file" :key="content" )
.space
@@ -75,6 +78,7 @@ export default {
refs: [],
notes: [],
is_on: false,
is_create_file_button_on: false,
// BUGFIX: this fucking shit does not want to update when a file is passed direstly from a saved component AAAAAAAAAAAAAAAAAA
ref_key: 0,
@@ -96,6 +100,10 @@ export default {
methods: {
async create( file ) {
await ilse.filesystem.file.write.async( ilse.path.join("second" , file), "" )
},
// Control the margins
get_note_style( note ) {
@@ -210,7 +218,8 @@ export default {
if( !has_text ) return
let time_id = ilse.utils.get_unique_date_id() // 20220120155758
let note = new ilse.classes.Note( `${time_id}: ${content}`)
let note = new ilse.classes.Note( `${time_id}: ${content}`)
printf( "note -> ", note )
this.notes.push( note )
this.save()
@@ -219,6 +228,7 @@ export default {
async save() {
let file = this.file
printf( "file -> ", file )
let is_buggy = !file
if( is_buggy ) {
@@ -227,6 +237,7 @@ export default {
}
let content = this.content
printf( "content -> ", content )
let notes = ""
let note_id_regexp = /^\s*[0-9]{13}.*/
@@ -235,6 +246,7 @@ export default {
// Non note content
let lines = content.split("\n")
printf( "lines -> ", lines )
let index = 0
let is_last
for( const line of lines ) {
@@ -256,6 +268,8 @@ export default {
// note content
for( const note of this.notes ) {
printf( "note.get() -> ", note.get() )
is_empty = !note.get()
if( is_empty ) continue
@@ -272,7 +286,9 @@ export default {
let content = " "
let time_id = ilse.utils.get_unique_date_id() // 20220120155758
printf( "time_id -> ", time_id )
let spaces = ilse.utils.get_depth_spaces( payload.note.depth )
printf( "spaces -> ", spaces )
let source = `${spaces}${time_id}: ${content}`
printf( "source -> ", source )
@@ -299,6 +315,7 @@ export default {
},
on_tab( payload ) {
printf( "on_tab -wdionqwdio -> ", payload )
payload.note.$depth( 1 )
},
@@ -378,11 +395,13 @@ export default {
try {
content = await ilse.filesystem.file.read.async( ilse.path.join("second" , this.file) )
this.content = content
this.is_create_file_button_on = false
this.check_for_existing_notes()
} catch(e) {
// ilse.notification.send( "New File", `Created file name: ${this.file}` )
// await ilse.filesystem.file.set( this.file, this.file )
// this.content = this.file
this.is_create_file_button_on = true
ilse.notification.send( "Error", `Could not find file: ${this.file}` )
}
this.is_on = true
144 changes: 110 additions & 34 deletions javascript/web/src/components/Graph.vue
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
<template lang="pug" >
.graph( tabindex="0" :ref="link" :id="link" :title="link" autofocus="autofocus" )

// img.img.is-pulled-right( src="@/assets/images/tool.svg" style="width: 20px; cursor: pointer; margin: 10px;" title="Network" v-popover="{ name: 'graph.config', position: 'left' }")
.layout
input.input( v-model="target" style="width: 100%; background: var( --background-color ); color: var( --text-color ); ")
.layout( style="position: relative; top: 25px; right: 25px; z-index: 100; " )
img.img.is-pulled-right( v-if="layouts[0] === 'cose'" :src="get_layout_image(layouts)" style="width: 30px; cursor: pointer;" :title="$t('cose_layout')" :style="get_layout_style('cose')" @click="select_next_layout()" )
img.img.is-pulled-right( v-if="layouts[0] === 'grid' " :src="get_layout_image(layouts)" style="width: 30px; cursor: pointer;" :title="$t('grid_layout')" :style="get_layout_style('grid')" @click="select_next_layout()" )
img.img.is-pulled-right( v-if="layouts[0] === 'circle'" :src="get_layout_image(layouts)" style="width: 30px; cursor: pointer;" :title="$t('circle_layout')" :style="get_layout_style('circle')" @click="select_next_layout()" )
img.img.is-pulled-right( v-if="layouts[0] === 'breadthfirst'" :src="get_layout_image(layouts)" style="width: 30px; cursor: pointer;" :title="$t('breadthfirst_layouot')" :style="get_layout_style('breadthfirst')" @click="select_next_layout()" )
img.img.is-pulled-right( v-if="layouts[0] === 'breadthfirst'" :src="get_layout_image(layouts)" style="width: 30px; cursor: pointer;" :title="$t('breadthfirst_layout')" :style="get_layout_style('breadthfirst')" @click="select_next_layout()" )
img.img.is-pulled-right( v-if="layouts[0] === 'concentric'" :src="get_layout_image(layouts)" style="width: 30px; cursor: pointer;" :title="$t('concentric_layout')" :style="get_layout_style('concentric')" @click="select_next_layout()" )

#cy( ref="cy" )

// button.button.slick-button( @click="run" ) run
</template>
<script>
// eslint-disable-next-line
@@ -27,10 +23,16 @@ const printf = console.log;
// Libs
// import createGraph from 'ngraph.graph'
// import fcose from "cytoscape-fcose"
// import Viva from "vivagraphjs"
import cytoscape from "cytoscape/dist/cytoscape.min.js"
// import fcose from "cytoscape-fcose"
import qtip from "cytoscape-qtip";
import dagre from "cytoscape-dagre";
// Install Libraries
cytoscape.use( qtip )
cytoscape.use( dagre )
export default {
@@ -39,7 +41,9 @@ export default {
data() {
return {
ilse: ilse,
target: "",
layouts: [
// "dagre",
"breadthfirst",
"grid",
"circle",
@@ -56,6 +60,18 @@ export default {
component: { type: Object, required: false, },
},
watch: {
target( target ) {
if( target.indexOf(".md") !== -1 ) {
this.run()
}
},
},
methods: {
select_next_layout() {
@@ -102,7 +118,7 @@ export default {
if( has_link ) {
this.generate_graph( link )
} else {
this.generate_graph( "Javascript.md" ) // Default k
this.generate_graph( this.target ) // Default k
}
},
@@ -132,7 +148,6 @@ export default {
add_links( file, elements ) {
let node = ilse.graph.graph.getNode( file )
printf( "node -> ", node )
let links = node.links
if( !links ) return elements
@@ -144,10 +159,11 @@ export default {
// Add what note links to
for( const [index, link] of links.entries() ) {
index % 2 === 0 ? bottom = 100 : bottom = -100
// index % 2 === 0 ? bottom = 100 : bottom = -100
note = ilse.notes.query( `${link.fromId}:` )[0]
normalized_name = ilse.utils.add_new_lines(note.content, 10)
printf( "normalized_name -> ", normalized_name )
// normalized_name = ilse.utils.add_new_lines(note.content, 10)
// normalized_name = ilse.utils.add_new_lines(note.content, 30)
// printf( "normalized_name -> ", normalized_name )
// var newStr = str.replace(/.{200}/g, "$0\n")
@@ -160,20 +176,23 @@ export default {
// name: note.content,
// name: normalized_name,
// name: normalized_name,
label: normalized_name,
// label: `${note.content}\nLorem`,
// label: note.id,
label: note.content,
name: note.content,
// label: note.content,
},
classes: 'bottom-left' ,
// classes: '' ,
// classes: "bottom-center",
// data: { label: normalized_name },
// nodeSep: 20,
position: {
// position: {
// x: bottom + ilse.utils.random_integer()
y: 0,
x: 0,
},
// y: 0,
// x: 0,
// },
// style: {
// 'background-color': 'red'
// },
@@ -213,6 +232,19 @@ export default {
style: [ // the stylesheet for the graph
{
selector: "node[label]",
style: {
label: "data(label)",
"font-size": "12",
color: "#000",
"overlay-padding": "6px",
'height': '20px',
"text-halign": "center",
"text-valign": "center"
}
},
{
selector: 'selected-node',
style: {
@@ -228,20 +260,27 @@ export default {
selector: 'node',
style: {
'background-color': '#666',
'height': '60px',
'width': '60px',
'overflow': 'auto',
// 'width' : 'data(size)',
// 'height' : 'data(size)',
'width' : '40px',
'height' : '40px',
/*'overflow': 'auto',*/
'border-color': 'black',
'text-background-opacity': 1,
'text-background-color': 'lightgray',
"overlay-padding": "6px",
"text-max-width": "200px",
"text-valign": "bottom",
"text-wrap": "ellipsis",
'text-align': 'left',
'text-hallign': 'left',
'float': 'left',
'text-align': 'top',
'text-hallign': 'top',
// 'float': 'left',
// 'label': 'data(id)',
// 'label': 'data(name)',
'label': 'data(label)',
/*'label': 'data(node)',*/
}
},
@@ -259,12 +298,43 @@ export default {
],
layout: {
// name: 'breadthfirst', // grid, circle, concentric, breadthfirst, cose,
/*
name: this.layouts[0], // grid, circle, concentric, breadthfirst, cose,
padding: 10,
nodeDimensionsIncludeLabels: true,
idealEdgeLength: 100,
edgeElasticity: 0.1,
rows: this.rows,
columns: 10,
cols: 10,
*/
name: this.layouts[0], // grid, circle, concentric, breadthfirst, cose,
fit: true,
// circle: true,
// directed: true, // up or down
// padding: 10,
spacingFactor: .3,
animate: true,
animationDuration: 500,
avoidOverlap: true,
nodeDimensionsIncludeLabels: true,
// columns: 3,
// cols: 3,
//Put all the clusters to the bottom row
// position: function (ele) {
// if (ele.data("type") === "cluster") {
// return { row: 3 };
// }
// return { row: 1 };
// },
}
})
@@ -300,10 +370,19 @@ export default {
})
*/
cy.nodes().each(function (node) {
node.qtip({
content: `${node.data("id")}`,
show: { event: "mouseenter mouseover" },
hide: { event: "mouseleave mouseout" }
});
});
cy.nodes().forEach( (el, index) => {
let y = el.position().y
let x = el.position().x
// let y = el.position().y
// let x = el.position().x
// let should = index % 2 === 0
// el.position({ y: y })
@@ -345,7 +424,7 @@ export default {
printf( "this.component -> ", this.component )
ilse.graph.generate()
setTimeout( () => { this.run() }, 1000 )
// setTimeout( () => { this.run() }, 1000 )
},
},
@@ -359,12 +438,9 @@ export default {
<style>
#cy {
margin-left: 20px;
width: 80%;
width: 98%;
height: 450px;
display: block;
margin-top: 10px;
border: 2px solid #666;
border-radius: 7px;
box-shadow: 2px 3px 5px rgba(0,0,0,.2);
}
3 changes: 0 additions & 3 deletions javascript/web/src/components/Home.vue
Original file line number Diff line number Diff line change
@@ -133,9 +133,6 @@ export default {
color: var( --text-color );
background: var( --background-color ) !important;
min-height: 100vh;
/*min-height: 100vh;*/
/*height: 100vh;*/
/*overflow: auto;*/
}
</style>
26 changes: 1 addition & 25 deletions javascript/web/src/components/Kanban.vue
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@
.card( v-for="( card, card_index ) in item.cards" :key=" 'card-' + card_index" draggable @dragenter.prevent @dragover.prevent @drop.prevent="on_drop($event, card, item)" style="height: auto; " )
input.input.centered( v-if="card_index === 0" v-model="item.name" )

img.is-pulled-right( v-if="card_index === 0" src="@/assets/images/point.svg")
// img.is-pulled-right( v-if="card_index === 0" src="@/assets/images/point.svg")
Note( :note="card" :options="{ 'is_tagless': true, 'hideBullet': true, style: 'padding: 4px; font-size: 14px;' }" )

@@ -73,33 +73,14 @@ export default {
},
set_content_to_tagless_plus_tags( item ) {
printf( "set_content_to_tagless_plus_tags -> item -> ", item )
printf( "set_content_to_tagless_plus_tags.get_tags() -> item -> ", item.get_tags() )
item.content = `${item.tagless} ${item.get_tags().join(" ")}`
printf( "item.content -> ", item.content )
},
set_obj( note ) {
printf( "note.tags -> ", note.tags )
printf( "note -> ", note )
printf( "note.tagless -> ", note.tagless )
printf( "note.proxy -> ", note.proxy )
// this.obj[note.id] = note.
},
on_drop( event, note, item ) {
printf( "note.content -> ", note.content )
let name = note.get_tags()[0]
let new_board = item.name
printf( "name -> ", name )
printf( "on_drop -> event -> ", event )
printf( "on_drop -> item -> ", item )
printf( "on_drop -> note -> ", note )
printf( "before -> note.content -> ", note.content )
note.content.replace( `#i/kanban/${this.board_name}/${name}`, `#i/kanban/${this.board_name}/${new_board}` )
printf( "after -> note.content -> ", note.content )
},
add_card( item, text ) {
@@ -124,7 +105,6 @@ export default {
if( !has_kanban_tag ) return
is_correct_name = note.content.indexOf( name ) !== -1
if( !is_correct_name ) return
this.set_obj( note )
notes.push( note )
})
@@ -151,10 +131,6 @@ export default {
return kanban_tags
},
get_board_names() {
},
// Board Name -> [ { name: board_name_1, notes: [] }, { name: board_name_2, notes: [] } ]
init( name ) {
// Can I use "query"?
6 changes: 4 additions & 2 deletions javascript/web/src/components/Note.vue
Original file line number Diff line number Diff line change
@@ -10,7 +10,9 @@
// show mode
.markdown( v-show="!inote.is_editable" v-html="get_html(options.is_tagless ? inote.tagless : inote.content )" @click="on_focus($event, inote)" :id="inote.id" @drop.prevent="add_file" @dragover.prevent )

Component.component-embed( v-if="get_component()" :component="get_component()" )
.component-part( v-if="get_component()" )
div( style="font-size: 1.5em; margin-left: 20px; padding: 0px; " )
Component.component-embed( :component="get_component()" :options="{ hide_bullet: true }" )

</template>
<script>
@@ -590,7 +592,7 @@ input:focus{
}
.markdown {
margin-bottom: 6px;
/*margin-bottom: 6px;*/
width: fit-content;
font-size: 1em;
}
52 changes: 48 additions & 4 deletions javascript/web/src/components/Notes.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
<template lang="pug" >
.notes
Note( :note="note" )
Note( :note="note" @on-enter="on_enter" @on-tab="on_tab" @on-shift-tab="on_shift_tab" @on-link-click="on_note_link_click" @on-esc="on_note_esc" @on-arrow-up="on_note_arrow_up" @on-arrow-down="on_note_arrow_down" @on-note-left-click="on_note_left_click" @on-note-middle-click="on_note_middle_click(note)" @on-note-right-click="on_note_right_click" )
.loop( v-for="( item, index ) in note.children" :key="index" :style="get_note_style(item)" )
// Note( :note="item" )
Notes( :note="item" )
Notes( :note="item" @on-enter="on_enter" @on-tab="on_tab" @on-shift-tab="on_shift_tab" @on-link-click="on_note_link_click" @on-esc="on_note_esc" @on-arrow-up="on_note_arrow_up" @on-arrow-down="on_note_arrow_down" @on-note-left-click="on_note_left_click" @on-note-middle-click="on_note_middle_click(note)" @on-note-right-click="on_note_right_click" )

</template>
<script>
@@ -41,12 +40,52 @@ export default {
methods: {
on_enter( payload ) {
this.$emit( "on-enter", payload )
},
on_tab( payload ) {
this.$emit( "on-tab", payload )
},
on_shift_tab( payload ) {
this.$emit( "on-shift-tab", payload )
},
on_note_link_click( payload ) {
this.$emit( "on-link-click", payload )
},
on_note_esc() {
this.$emit( "on-esc" )
},
on_note_arrow_up( payload ) {
this.$emit( "on-arrow-up", payload )
},
on_note_arrow_down( payload ) {
this.$emit( "on-arrow-down", payload )
},
on_note_left_click( payload ) {
this.$emit( "on-left-click", payload )
},
on_note_middle_click( payload ) {
this.$emit( "on-middle-click", payload )
},
on_note_right_click( payload ) {
this.$emit( "on-right-click", payload )
},
// Control the margins
get_note_style( note ) {
// let style = `display: flex;`
let style = ``
if( note.depth ) style += `margin-left: ${20 * note.depth}px !important; `
if( note.depth ) style += `margin-left: ${15 * note.depth}px !important; `
return style
},
@@ -65,4 +104,9 @@ export default {
</script>
<style scoped>
.notes .loop {
border-left: 1px solid var( --text-color );
}
</style>
1 change: 1 addition & 0 deletions javascript/web/src/components/TopMenu.vue
Original file line number Diff line number Diff line change
@@ -54,6 +54,7 @@

p {{folder}}
img( src="@/assets/images/plus.svg" style="width: 30px; display: block; margin: 0 auto;" @click="add_target_directory" :title="$t('add_folder')" )
br

</template>
<script>
328 changes: 37 additions & 291 deletions javascript/web/yarn.lock

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
@@ -33,6 +33,7 @@ This started with frustration not only with lock-in but the lack of extensabilit

| Platform | How | Gif |
|--------------|-----------|------------|
| Web Demo | [Check](https://ilse-langnar.github.io/notebook/demo/index.html) | Learn More | |
| Web(.html) | [Download](https://github.com/ilse-langnar/notebook/releases/download/1.0.10/demo.tar-1.0.11.gz) | Learn More | |
| Desktop Linux(AppImage) | [Download](https://github.com/ilse-langnar/notebook/releases/download/0.8/ilse-langnar-notebook-0.1.8.AppImage) | ![Demo](https://raw.githubusercontent.com/ilse-langnar/notebook/dev/docs/desktop-linux.gif) |
| Desktop Windows(.exe) | [Download](https://github.com/ilse-langnar/notebook/releases/download/1.0.10/ilse-langnar-notebook.Setup.1.0.11.exe) |
@@ -70,7 +71,7 @@ This started with frustration not only with lock-in but the lack of extensabilit
| File Reference | Reference files inside notes. | ![File Embed](https://raw.githubusercontent.com/ilse-langnar/notebook/dev/docs/feature-file-embed.gif) |
| Multiple Components | You can check a file while looking at the calendar and your daily notes. | ![Multiple Components](https://raw.githubusercontent.com/ilse-langnar/notebook/dev/docs/feature-multiple-components.gif) |
| Homepage | TODO | |
| Graph | TODO | |
| Graph | Visualize relationship between notes, files, media and more. | ![Graph](https://raw.githubusercontent.com/ilse-langnar/notebook/dev/docs/feature-graph.gif) |
| Keyboard Shortcut | Bind shortcuts from simple such as `ctrl+s` to complex such as `ctrl+space i z` | | ![Keyboard Shortcuts](https://raw.githubusercontent.com/ilse-langnar/notebook/dev/docs/feature-shortcuts.gif) |
| Commands and Command Pallet | See all the available commands with the command pallet, execute any function with commands | ![Command Pallet](https://raw.githubusercontent.com/ilse-langnar/notebook/dev/docs/feature-command-pallet.gif) |
| Study Tools | See "Studying with Ilse" for more |

0 comments on commit 6e1ab56

Please sign in to comment.