diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 2e53ff1..9b8e2fb 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -144,6 +144,7 @@ name = "apographe" version = "0.1.0" dependencies = [ "comrak", + "html_tag", "serde", "serde_json", "shellexpand", @@ -1582,6 +1583,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "html_tag" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "258c462501ea394856d3c6cf7ca16f384dfb928766617bf018af0068c6935dee" + [[package]] name = "http" version = "1.1.0" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 3e97124..29393c6 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -26,4 +26,5 @@ comrak = "0.29.0" tauri-plugin-fs = "2" tauri-plugin-log = "2" shellexpand = "3.1.0" +html_tag = "0.1.3" diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index a59c361..35ff5b2 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,9 +1,16 @@ -use std::path::Path; - use comrak::{format_html, nodes::NodeValue, parse_document, Arena, Options}; +use html_tag::HtmlTag; use shellexpand; -use tauri::Manager; +use std::{ + collections::BTreeMap, + env, + ffi::{OsStr, OsString}, + fs, + path::{absolute, Path}, +}; +use tauri::{ipc::IpcResponse, Manager}; use tauri_plugin_fs::FsExt; + // Learn more about Tauri commands at https://tauri.app/develop/calling-rust/ #[tauri::command] fn greet(name: &str) -> String { @@ -11,7 +18,7 @@ fn greet(name: &str) -> String { } #[tauri::command] -fn parse_markdown(document: &str, pathtemplate: &str) -> String { +fn parse_markdown(document: &str, pathtemplate: &str, basepath: &str) -> String { let mut rendered_markdown: String = String::new(); let path = "/foo/bar.txt"; println!("{:?}", shellexpand::full(path)); @@ -25,9 +32,16 @@ fn parse_markdown(document: &str, pathtemplate: &str) -> String { let root = parse_document(&arena, document, &options); // Iterate over all the descendants of root. + env::set_current_dir(basepath); for node in root.descendants() { if let NodeValue::Image(ref mut image_node) = node.data.borrow_mut().value { - if let Ok(resolved_path) = shellexpand::full(&image_node.url) { + let image_path = Path::new(&image_node.url).to_path_buf(); + let absolute_image_path = absolute(image_node.url.clone()); + let absolute_image_path = +.unwrap_or(image_path) + .as_path() + .to_string_lossy() + if let Ok(resolved_path) = shellexpand::full(&absolute_image_path) { image_node.url = pathtemplate.replace("FILEPATH", &resolved_path); } } @@ -39,7 +53,100 @@ fn parse_markdown(document: &str, pathtemplate: &str) -> String { return rendered_markdown.to_owned(); // String::from_str("lololo").unwrap() } +//
+// +//
+fn add_dir_tree_node(path: &Path, filter: &Vec) -> HtmlTag { + let mut html = HtmlTag::new("div") + .with_class("filetree-node") + .with_id(&format!( + "{}", + Path::new(path) + .file_name() + .unwrap_or_default() + .to_string_lossy() + )) + .with_attribute("expanded", "false") + .with_child( + HtmlTag::new("button") + .with_class("filetree-directory-button") + .with_child( + HtmlTag::new("img") + .with_class("filetree-icon") + .with_attribute("src", "images/directory.svg"), + ) + .with_child( + HtmlTag::new("a").with_body( + &Path::new(path) + .file_name() + .unwrap_or_default() + .to_string_lossy(), + ), + ), + ); + if let Ok(entries) = fs::read_dir(path) { + for dir_entry_res in entries { + println!("{:?}", dir_entry_res); + if let Ok(dir_entry) = dir_entry_res { + if let Ok(metadata) = fs::metadata(dir_entry.path()) { + if metadata.is_file() { + let mut file_div = HtmlTag::new("div") + .with_class("filetree-node") + .with_id(&format!("{}", dir_entry.path().to_string_lossy())) + .with_attribute("style", "visibility: hidden; height: 0px;"); + let mut file_button = + HtmlTag::new("button").with_class("filetree-file-button"); + match dir_entry + .path() + .extension() + .unwrap_or_default() + .to_string_lossy() + .to_string() + .as_str() + { + "md" => file_button.add_child( + HtmlTag::new("img") + .with_class("filetree-icon") + .with_attribute("src", "images/markdown.svg"), + ), + + _ => file_button.add_child( + HtmlTag::new("img") + .with_class("filetree-icon") + .with_attribute("src", "images/file.svg"), + ), + }; + + file_button.add_child( + HtmlTag::new("a").with_body(&dir_entry.file_name().to_string_lossy()), + ); + file_div.add_child(file_button); + + html.add_child(file_div) + } else if metadata.is_dir() { + html.add_child( + add_dir_tree_node(&dir_entry.path(), &filter) + .with_attribute("style", "visibility: hidden; height: 0px;"), // .with_style("visibility", "hidden") + // .with_style("height", "0px"), + ); + } + } + } + } + } + return html; +} +#[tauri::command] +fn dir_tree_html(basepath: &str, filter: Vec) -> String { + match shellexpand::full(basepath) { + Ok(path) => add_dir_tree_node(&Path::new(&path.into_owned()), &filter).to_html(), + + Err(_) => String::new(), + } +} #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { tauri::Builder::default() @@ -54,8 +161,7 @@ pub fn run() { Ok(()) }) - .invoke_handler(tauri::generate_handler![greet]) - .invoke_handler(tauri::generate_handler![parse_markdown]) + .invoke_handler(tauri::generate_handler![dir_tree_html, parse_markdown]) .run(tauri::generate_context!()) .expect("error while running tauri application"); } diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 046d436..d9cb6be 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -11,6 +11,7 @@ "windows": [ { "title": "apographe", + "decorations": false, "width": 800, "height": 600 } diff --git a/src/filesystem.js b/src/filesystem.js new file mode 100644 index 0000000..f0c4995 --- /dev/null +++ b/src/filesystem.js @@ -0,0 +1,79 @@ +const { convertFileSrc, invoke } = window.__TAURI__.core; +const { homeDir, join } = window.__TAURI__.path; +const { readTextFile } = window.__TAURI__.fs; + +function handle_file_select(filename){ + if (filename.endsWith("md")){ + readTextFile(convertFileSrc(filename) ).then( + (ret)=>{ + var tag_id = document.getElementById('markdown_input'); + tag_id.innerHTML = "
".concat("", ret).concat("", "
"); + } + ); + var tag_id = document.getElementById('rendered_markdown'); + tag_id.dispatchEvent(new Event("input")); + } +} + +function dropdown(id) { + var dropdown_element = document.getElementById(id); + var dropdown_children = dropdown_element.children; + console.log(dropdown_element.getAttribute("expanded")); + if (dropdown_element.getAttribute("expanded") == "false") { + dropdown_element.setAttribute("expanded", "true"); + } + else{ + dropdown_element.setAttribute("expanded", "false"); + } + for (var i = 0; i < dropdown_children.length; i++) { + var child = dropdown_children[i]; + console.log(child.id); + if (child.className === "filetree-node") { + if (document.getElementById(id).getAttribute("expanded") == "true") { + document.getElementById(child.id).style.visibility = "visible"; + document.getElementById(child.id).style.height = "auto"; + } else { + document.getElementById(child.id).style.visibility = "hidden"; + document.getElementById(child.id).style.height = 0; + } + } + } + +} +window.onload = function () { + invoke("dir_tree_html", { basepath: "~/Documents/Knowledgebase", filter: ["*"]}).then( + (ret)=>{ + var tag_id = document.getElementById('filetree'); + tag_id.innerHTML = ret; + } + ) +} +let filetree = document.getElementById('filetree'); +// Options for the observer (which mutations to observe) +const config = { attributes: true, childList: true, subtree: true }; + +// Callback function to execute when mutations are observed +const callback = (mutationList, observer) => { + var anchors = document.getElementsByClassName("filetree-directory-button"); + for (var i = 0; i < anchors.length; i++) { + var anchor = anchors[i]; + anchor.onclick = function () { + dropdown(this.parentElement.id); + }; + }; + var anchors = document.getElementsByClassName("filetree-file-button"); + for (var i = 0; i < anchors.length; i++) { + var anchor = anchors[i]; + anchor.onclick = function () { + handle_file_select(this.parentElement.id); + }; + }; + +}; + +// Create an observer instance linked to the callback function +const observer = new MutationObserver(callback); + +// Start observing the target node for configured mutations +observer.observe(filetree, config); + diff --git a/src/images/directory.svg b/src/images/directory.svg new file mode 100644 index 0000000..174491a --- /dev/null +++ b/src/images/directory.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + diff --git a/src/images/dropdown.svg b/src/images/dropdown.svg new file mode 100644 index 0000000..231629b --- /dev/null +++ b/src/images/dropdown.svg @@ -0,0 +1,23 @@ + + + + + + + + + diff --git a/src/images/file.svg b/src/images/file.svg new file mode 100644 index 0000000..21269a3 --- /dev/null +++ b/src/images/file.svg @@ -0,0 +1,26 @@ + + + + + + + + + + diff --git a/src/images/markdown.svg b/src/images/markdown.svg new file mode 100644 index 0000000..10b51c0 --- /dev/null +++ b/src/images/markdown.svg @@ -0,0 +1,55 @@ + + + + + + + + + + + M + + + + diff --git a/src/images/menu_button.svg b/src/images/menu_button.svg new file mode 100644 index 0000000..32f9392 --- /dev/null +++ b/src/images/menu_button.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + diff --git a/src/images/path6.svg b/src/images/path6.svg new file mode 100644 index 0000000..174491a --- /dev/null +++ b/src/images/path6.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + diff --git a/src/index.html b/src/index.html index 472b9f3..6617c79 100644 --- a/src/index.html +++ b/src/index.html @@ -1,33 +1,68 @@ - - - - - Tauri App - - - - - -
-
- -
-
- -
-
-
+ + + + + Tauri App + + + + + + + + -
-
-
-
- - + +
+ + +

This modal dialog has a groovy backdrop!

+
+ +
+ +
+
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main.js b/src/main.js index 30080d4..c5ce8c3 100644 --- a/src/main.js +++ b/src/main.js @@ -1,5 +1,4 @@ const { convertFileSrc, invoke } = window.__TAURI__.core; -// const { invoke } = window.__TAURI__.core; const { homeDir, join } = window.__TAURI__.path; const { readFile } = window.__TAURI__.fs; @@ -9,16 +8,10 @@ const filePath = await join(appDataDirPath, 'Pictures/wallpaper.png'); const assetUrl = convertFileSrc(filePath); let text = ""; -// window.addEventListener("DOMCharacterDataModified", () => { - // var tag_id = document.getElementById('rendered_markdown'); - // tag_id.innerHTML = "

HI

" -// window.addEventListener("DOMContentLoaded", () => { -let textarea = document.getElementById('markdown_input'); - - let placeholder_path = "FILEPATH"; let path_template = convertFileSrc(placeholder_path); +let textarea = document.getElementById('markdown_input'); textarea.addEventListener('input', ()=> { text = textarea.innerText; var tag_id = document.getElementById('rendered_markdown'); @@ -32,31 +25,7 @@ textarea.addEventListener('input', ()=> { // }); }); -document.getElementById("hide-sidebar").onclick = function() {toggle_visibility("sidebar");}; -function toggle_visibility(id) { - if (document.getElementById(id).style.visibility == "hidden"){ - document.getElementById(id).style.visibility = "visible"; - var style = window.getComputedStyle(document.body); - document.getElementById(id).style.width = style.getPropertyValue("--sidebar-width"); - }else{ - - document.getElementById(id).style.visibility = "hidden"; - document.getElementById(id).style.width = 0; - } - -} -function handleShortcut(event) { - var markdown_editor = document.getElementById('markdown_input'); - if (document.activeElement === markdown_editor){ - if (event.ctrlKey) { - if (event.key === "l"){ - event.preventDefault(); - } - } - } -} -document.addEventListener("keydown", handleShortcut); // Random tree // const N = 300; // const gData = { diff --git a/src/styles.css b/src/styles.css index 58c6701..001f093 100644 --- a/src/styles.css +++ b/src/styles.css @@ -1,31 +1,35 @@ - - .logo.vanilla:hover { filter: drop-shadow(0 0 2em #ffe21c); } + :root { - --main-bg-color: #4f4f4f; - --sidebar-width: 3em; - font-family: Avenir, Helvetica, Arial, sans-serif; - font-size: 16px; - line-height: 24px; + --main-bg-color: #2f2f2f; + --sidebar-width: 3em; + --highlight-color: #5f5f5f; + --text-color: #ffffff; - color: #f6f6f6; - background-color: var(--main-bg-color); + font-family: Avenir, Helvetica, Arial, sans-serif; + font-size: 16px; + line-height: 24px; + + color: #f6f6f6; + background-color: var(--main-bg-color); + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + -webkit-text-size-adjust: 100%; - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - -webkit-text-size-adjust: 100%; - } -*{ + +* { box-sizing: border-box; padding: 0; margin: 0; } + .container { height: 100%; margin: 0; @@ -38,35 +42,41 @@ .col { - width: 50%; - padding: 0.5em; - margin: .1em; - border: solid; - border-radius: .5em; + width: 50%; + padding: 0.5em; + margin: .1em; + border: solid; + border-radius: .5em; } -#markdown_input -{ - grid-column: 1; - grid-row: 1; - text-align: left; - /*float:left;*/ - color: #f6f6f6; - background: var(--main-bg-color); -} -#rendered_markdown { - grid-column: 2; - grid-row: 1; - - /*float:right;*/ - text-align: left; - color: #f6f6f6; - background-color: var(--main-bg-color); - img { - width: 100%; - } +#markdown_input { + grid-column: 1; + grid-row: 1; + text-align: left; + /*float:left;*/ + color: #f6f6f6; + background: var(--main-bg-color); + overflow: scroll; } -.main_editor{ + +#rendered_markdown { + grid-column: 2; + grid-row: 1; + + + /*float:right;*/ + text-align: left; + color: #f6f6f6; + background-color: var(--main-bg-color); + + img { + width: 100%; + } + + overflow: scroll; +} + +.main_editor { width: 100%; text-align: center; font-size: 16px; @@ -78,10 +88,11 @@ color: #f6f6f6; background-color: var(--main-bg-color); } + h1 { text-align: left; line-height: 18px; - margin-top: 0.067em; + margin-top: 0.067em; margin-bottom: 0.067em; color: red; } @@ -94,22 +105,26 @@ li { } .sidebar_button { - width: 100%; - background-color: var(--main-bg-color); - border: none; + width: 100%; + background-color: var(--main-bg-color); + border: none; } .sidebar_icon { - width: 100%; + width: 100%; } + .topbar_button { - height: 2em; - background-color: var(--main-bg-color); - border: none; + height: 2em; + background-color: transparent; + border: none; } + .topbar_icon { - height: 100%; + height: 100%; + background-color: transparent; } + @media (prefers-color-scheme: dark) { :root { color: #f6f6f6; @@ -117,22 +132,61 @@ li { } } + #main_editor { - display: flex; - width: 100%; - height: 100%; + display: flex; + width: 100%; + height: 100%; } .main { - display: flex; - height:100vh; - flex-direction: column; + display: flex; + height: 95vh; + flex-direction: column; } #sidebar { - visibility: visible; - width: var(--sidebar-width); - transition: all 0.1s ease-out; + visibility: visible; + width: var(--sidebar-width); + transition: all 0.1s ease-out; } + +.filetree { + width: 10em; + overflow-x: scroll; + overflow-y: scroll; +} + +.filetree-directory-button, +.filetree-file-button { + background-color: transparent; + border: none; + width: 100%; + height: inherit; + text-align: left; + transition: all 0.01s ease-out; + white-space: nowrap; + overflow-y: visible; + color: var(--text-color); + +} + +.filetree-icon { + height: 1em; + background-color: transparent; + margin-right: 5px; +} + + +.filetree_expand { + background-color: transparent; + border: none; +} + +.filetree-file-button:hover, +.filetree-directory-button:hover { + background-color: var(--highlight-color); + /* Green */ +} \ No newline at end of file diff --git a/src/ui.js b/src/ui.js new file mode 100644 index 0000000..2ad4199 --- /dev/null +++ b/src/ui.js @@ -0,0 +1,25 @@ +function toggle_visibility(id) { + if (document.getElementById(id).style.visibility == "hidden") { + document.getElementById(id).style.visibility = "visible"; + var style = window.getComputedStyle(document.body); + document.getElementById(id).style.width = style.getPropertyValue("--sidebar-width"); + } else { + document.getElementById(id).style.visibility = "hidden"; + document.getElementById(id).style.width = 0; + } +} +function handleShortcut(event) { + var markdown_editor = document.getElementById("markdown_input"); + + if (document.activeElement === markdown_editor) { + if (event.ctrlKey) { + if (event.key === "l") { + event.preventDefault(); + } + } + } +} +document.addEventListener("keydown", handleShortcut); +document.getElementById("hide-sidebar").onclick = function () { + toggle_visibility("sidebar"); +};