propagated use of config home path to other systems. file loading now works using rust instead of js

This commit is contained in:
Iaphetes 2025-03-09 09:03:40 +01:00
parent 62918416ee
commit 11bd003298
11 changed files with 1007 additions and 1000 deletions

1460
src-tauri/Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -21,6 +21,7 @@ tauri-build = { version = "2", features = [] }
[dependencies] [dependencies]
tauri = { version = "2", features = ["protocol-asset", "unstable"] } tauri = { version = "2", features = ["protocol-asset", "unstable"] }
tauri-plugin-shell = "2" tauri-plugin-shell = "2"
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
serde_json = "1" serde_json = "1"

View file

@ -6,13 +6,17 @@ use std::{
use sqlx::{migrate::MigrateDatabase, Sqlite, SqlitePool}; use sqlx::{migrate::MigrateDatabase, Sqlite, SqlitePool};
use tauri::{ipc::RuntimeCapability, App, AssetResolver, Manager, Url}; use tauri::{ipc::RuntimeCapability, App, AssetResolver, Manager, Url};
use crate::get_basepath;
async fn populate_file_db(db: &SqlitePool) {} async fn populate_file_db(db: &SqlitePool) {}
#[tauri::command] #[tauri::command]
pub async fn initialize_database( pub async fn initialize_database(
app_handle: tauri::AppHandle, app_handle: tauri::AppHandle,
basepath: String, basepath: String,
pathtemplate: String, pathtemplate: String,
) { ) {
if let Some(basepath) = get_basepath(app_handle.clone()) {
let db_path = Path::new("Documents") let db_path = Path::new("Documents")
.join(Path::new("Knowledgebase")) .join(Path::new("Knowledgebase"))
.join("db.sqlite"); .join("db.sqlite");
@ -61,7 +65,10 @@ pub async fn initialize_database(
.execute(&db) .execute(&db)
.await .await
.unwrap(); .unwrap();
}
} }
#[tauri::command] #[tauri::command]
async fn store_diff(diff: String) {} async fn store_diff(diff: String) {
}

View file

@ -0,0 +1,19 @@
use tauri::{ipc::RuntimeCapability, App, AssetResolver, Manager, Url};
use std::fs::{read_to_string};
use std::path::Path;
use crate::get_basepath;
#[tauri::command]
pub async fn save(
app_handle: tauri::AppHandle,
path: String, content: String) {}
#[tauri::command]
pub async fn load(
path: String) -> Result<String, String> {
println!("loading file");
read_to_string(path).map_err(|e| e.to_string())
}

View file

@ -1,3 +1,4 @@
use crate::get_basepath;
use html_tag::HtmlTag; use html_tag::HtmlTag;
use shellexpand; use shellexpand;
use std::{ use std::{
@ -5,11 +6,11 @@ use std::{
path::Path, path::Path,
}; };
#[tauri::command] #[tauri::command]
pub fn dir_tree_html(basepath: &str, filter: Vec<String>) -> String { pub fn dir_tree_html(app_handle: tauri::AppHandle, filter: Vec<String>) -> String {
match shellexpand::full(basepath) { if let Some(basepath) = get_basepath(app_handle) {
Ok(path) => add_dir_tree_node(&Path::new(&path.into_owned()), &filter).to_html(), add_dir_tree_node(&Path::new(&basepath), &filter).to_html()
} else {
Err(_) => String::new(), String::new()
} }
} }
fn add_dir_tree_node(path: &Path, filter: &Vec<String>) -> HtmlTag { fn add_dir_tree_node(path: &Path, filter: &Vec<String>) -> HtmlTag {

View file

@ -1,6 +1,7 @@
mod config; mod config;
mod database; mod database;
mod file_access; mod file_access;
mod file_handler;
mod file_tree; mod file_tree;
mod markdown_parser; mod markdown_parser;
mod search; mod search;
@ -14,7 +15,7 @@ use std::env;
use std::sync::Mutex; use std::sync::Mutex;
use tauri::Manager; use tauri::Manager;
use tauri_plugin_fs::FsExt; use tauri_plugin_fs::FsExt;
use file_handler::load;
#[cfg_attr(mobile, tauri::mobile_entry_point)] #[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() { pub fn run() {
tauri::Builder::default() tauri::Builder::default()
@ -40,6 +41,7 @@ pub fn run() {
search_files, search_files,
get_basepath, get_basepath,
set_basepath, set_basepath,
load
]) ])
.run(tauri::generate_context!()) .run(tauri::generate_context!())
.expect("error while running tauri application"); .expect("error while running tauri application");

View file

@ -1,2 +0,0 @@
#[tauri::command]
pub async fn save(path: String, content: String) {}

View file

@ -2,30 +2,29 @@ const { convertFileSrc, invoke } = window.__TAURI__.core;
import { handle_file_select } from "./filesystem.js"; import { handle_file_select } from "./filesystem.js";
var search_input = document.getElementById("file-search-dialog-input"); var search_input = document.getElementById("file-search-dialog-input");
search_input.addEventListener('input', () => { search_input.addEventListener("input", () => {
search_files(); search_files();
}); });
function search_files() {
function search_files(){
var text = search_input.innerText; var text = search_input.innerText;
invoke("search_files", { searchstring: text, basepath: "$HOME/Documents/Knowledgebase", filter: ["md"]}).then( invoke("search_files", {
(ret) => { searchstring: text,
var tag_id = document.getElementById('file-search-results'); basepath: "$HOME/Documents/Knowledgebase",
var result_div = ""; filter: ["md"],
console.log(ret); }).then((ret) => {
ret.forEach(element => { var tag_id = document.getElementById("file-search-results");
result_div += element; var result_div = "";
}); console.log(ret);
console.log(result_div); ret.forEach((element) => {
tag_id.innerHTML = result_div; result_div += element;
// tag_id.innerHTML = assetUrl.concat(" ", ' \n <img src="'.concat("", assetUrl).concat("", '" alt="Girl in a jacket" width="500" height="600">')) });
} console.log(result_div);
); tag_id.innerHTML = result_div;
});
} }
let filetree = document.getElementById("file-search-results");
let filetree = document.getElementById('file-search-results');
// Options for the observer (which mutations to observe) // Options for the observer (which mutations to observe)
const config = { attributes: true, childList: true, subtree: true }; const config = { attributes: true, childList: true, subtree: true };
@ -35,11 +34,10 @@ const callback = (mutationList, observer) => {
var anchors = document.getElementsByClassName("file-search-button"); var anchors = document.getElementsByClassName("file-search-button");
for (var i = 0; i < anchors.length; i++) { for (var i = 0; i < anchors.length; i++) {
var anchor = anchors[i]; var anchor = anchors[i];
anchor.onclick = function() { anchor.onclick = function () {
handle_file_select(this.parentElement.id); handle_file_select(this.parentElement.id);
}; };
}; }
}; };
const observer = new MutationObserver(callback); const observer = new MutationObserver(callback);

View file

@ -5,14 +5,12 @@ import { render_markdown } from "./main.js";
var selected_file = ""; var selected_file = "";
export function handle_file_select(filename) { export function handle_file_select(filename) {
if (filename.endsWith("md")) { if (filename.endsWith("md")) {
readTextFile(convertFileSrc(filename)).then( invoke("load", { path: filename }).then((ret) => {
(ret) => { var tag_id = document.getElementById("markdown_input");
var tag_id = document.getElementById('markdown_input'); tag_id.innerHTML = "<pre>".concat("", ret).concat("", "</pre>");
tag_id.innerHTML = "<pre>".concat("", ret).concat("", "</pre>"); render_markdown();
render_markdown(); selected_file = filename;
selected_file = filename; });
}
);
} }
} }
@ -20,17 +18,15 @@ export function save_file() {
console.log(selected_file); console.log(selected_file);
} }
document.getElementById("save-file").onclick = function () { document.getElementById("save-file").onclick = function () {
save_file();
save_file(); };
}
function dropdown(id) { function dropdown(id) {
var dropdown_element = document.getElementById(id); var dropdown_element = document.getElementById(id);
var dropdown_children = dropdown_element.children; var dropdown_children = dropdown_element.children;
console.log(dropdown_element.getAttribute("expanded")); console.log(dropdown_element.getAttribute("expanded"));
if (dropdown_element.getAttribute("expanded") == "false") { if (dropdown_element.getAttribute("expanded") == "false") {
dropdown_element.setAttribute("expanded", "true"); dropdown_element.setAttribute("expanded", "true");
} } else {
else {
dropdown_element.setAttribute("expanded", "false"); dropdown_element.setAttribute("expanded", "false");
} }
for (var i = 0; i < dropdown_children.length; i++) { for (var i = 0; i < dropdown_children.length; i++) {
@ -46,17 +42,17 @@ function dropdown(id) {
} }
} }
} }
} }
window.onload = function() { window.onload = function () {
invoke("dir_tree_html", { basepath: "~/Documents/Knowledgebase", filter: ["*"] }).then( invoke("dir_tree_html", {
(ret) => { basepath: "~/Documents/Knowledgebase",
var tag_id = document.getElementById('filetree'); filter: ["*"],
tag_id.innerHTML = ret; }).then((ret) => {
} var tag_id = document.getElementById("filetree");
) tag_id.innerHTML = ret;
} });
let filetree = document.getElementById('filetree'); };
let filetree = document.getElementById("filetree");
// Options for the observer (which mutations to observe) // Options for the observer (which mutations to observe)
const config = { attributes: true, childList: true, subtree: true }; const config = { attributes: true, childList: true, subtree: true };
@ -65,18 +61,17 @@ const callback = (mutationList, observer) => {
var anchors = document.getElementsByClassName("filetree-directory-button"); var anchors = document.getElementsByClassName("filetree-directory-button");
for (var i = 0; i < anchors.length; i++) { for (var i = 0; i < anchors.length; i++) {
var anchor = anchors[i]; var anchor = anchors[i];
anchor.onclick = function() { anchor.onclick = function () {
dropdown(this.parentElement.id); dropdown(this.parentElement.id);
}; };
}; }
var anchors = document.getElementsByClassName("filetree-file-button"); var anchors = document.getElementsByClassName("filetree-file-button");
for (var i = 0; i < anchors.length; i++) { for (var i = 0; i < anchors.length; i++) {
var anchor = anchors[i]; var anchor = anchors[i];
anchor.onclick = function() { anchor.onclick = function () {
handle_file_select(this.parentElement.id); handle_file_select(this.parentElement.id);
}; };
}; }
}; };
// Create an observer instance linked to the callback function // Create an observer instance linked to the callback function
@ -84,4 +79,3 @@ const observer = new MutationObserver(callback);
// Start observing the target node for configured mutations // Start observing the target node for configured mutations
observer.observe(filetree, config); observer.observe(filetree, config);

View file

@ -5,25 +5,22 @@ let text = "";
let placeholder_path = "FILEPATH"; let placeholder_path = "FILEPATH";
let path_template = convertFileSrc(placeholder_path); let path_template = convertFileSrc(placeholder_path);
let textarea = document.getElementById('markdown_input'); let textarea = document.getElementById("markdown_input");
// TODO move to place, where the knowledgebase is created... // TODO move to place, where the knowledgebase is created...
invoke("initialize_database", { basepath: "~/Documents/Knowledgebase", pathtemplate: path_template }).then( invoke("initialize_database", {
(ret) => { basepath: "~/Documents/Knowledgebase",
} pathtemplate: path_template,
); }).then((ret) => {});
invoke("get_basepath").then( invoke("get_basepath").then((ret) => {
(ret) => { if (!ret) {
if (!ret){ const setup_dialog = document.getElementById("setup-dialog");
const setup_dialog = document.getElementById("setup-dialog"); setup_dialog.show();
setup_dialog.show(); } else {
console.log(ret);
}else{
console.log(ret);
}
} }
) });
document.getElementById("knowledgebase-button").onclick = async function () { document.getElementById("knowledgebase-button").onclick = async function () {
const file = await open({ const file = await open({
multiple: false, multiple: false,
@ -32,33 +29,31 @@ document.getElementById("knowledgebase-button").onclick = async function () {
const path_text = document.getElementById("knowledgebase-path"); const path_text = document.getElementById("knowledgebase-path");
path_text.innerText = file; path_text.innerText = file;
invoke("set_basepath", {path: file}).then( invoke("set_basepath", { path: file }).then((ret) => {
(ret) => { if (ret) {
if (ret){ const setup_dialog = document.getElementById("setup-dialog");
const setup_dialog = document.getElementById("setup-dialog"); console.log("hiding");
console.log("hiding"); setup_dialog.close();
setup_dialog.close(); location.reload();
}
} }
); });
console.log(file); console.log(file);
}; };
// //
export function render_markdown() { export function render_markdown() {
text = textarea.innerText; text = textarea.innerText;
invoke("parse_markdown", { document: text, pathtemplate: path_template, basepath: "$HOME/Documents/Knowledgebase" }).then( invoke("parse_markdown", {
(ret) => { document: text,
var tag_id = document.getElementById('rendered_markdown'); pathtemplate: path_template,
tag_id.innerHTML = "<pre>".concat("", ret).concat("", "</pre>"); }).then((ret) => {
// tag_id.innerHTML = assetUrl.concat(" ", ' \n <img src="'.concat("", assetUrl).concat("", '" alt="Girl in a jacket" width="500" height="600">')) var tag_id = document.getElementById("rendered_markdown");
} tag_id.innerHTML = "<pre>".concat("", ret).concat("", "</pre>");
); });
} }
textarea.addEventListener('input', () => { textarea.addEventListener("input", () => {
render_markdown(); render_markdown();
}); });
// Random tree // Random tree
// const N = 300; // const N = 300;
// const gData = { // const gData = {

View file

@ -1,282 +1,278 @@
.logo.vanilla:hover { .logo.vanilla:hover {
filter: drop-shadow(0 0 2em #ffe21c); filter: drop-shadow(0 0 2em #ffe21c);
} }
:root { :root {
--main-bg-color: #2f2f2f; --main-bg-color: #2f2f2f;
--highlight-color: #3f3f3f; --highlight-color: #3f3f3f;
--bright-highlight-color: #4f4f4f; --bright-highlight-color: #4f4f4f;
--text-color: #f6f6f6; --text-color: #f6f6f6;
--accent-color: #5f5f5f; --accent-color: #5f5f5f;
--sidebar-width: 3em; --sidebar-width: 3em;
--filetree-width: 10em; --filetree-width: 10em;
font-family: Avenir, Helvetica, Arial, sans-serif; font-family: Avenir, Helvetica, Arial, sans-serif;
font-size: 30px; font-size: 30px;
line-height: 24px; line-height: 24px;
color: #f6f6f6; color: #f6f6f6;
background-color: var(--main-bg-color); background-color: var(--main-bg-color);
font-synthesis: none; font-synthesis: none;
text-rendering: optimizeLegibility; text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%; -webkit-text-size-adjust: 100%;
} }
* { * {
box-sizing: border-box; box-sizing: border-box;
padding: 0; padding: 0;
margin: 0; margin: 0;
} }
.container { .container {
height: 100%; height: 100%;
max-width: 100%; max-width: 100%;
margin: 0; margin: 0;
padding-top: 1vh; padding-top: 1vh;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
text-align: left; text-align: left;
align-items: stretch; align-items: stretch;
} }
#main_editor { #main_editor {
width: 100%; width: 100%;
font-size: 16px; font-size: 16px;
line-height: 18px; line-height: 18px;
display: flex; display: flex;
height: 100%; height: 100%;
width: 100%; width: 100%;
color: var(--text-color); color: var(--text-color);
background-color: var(--main-bg-color); background-color: var(--main-bg-color);
float: right; float: right;
overflow: hidden; overflow: hidden;
} }
.col { .col {
flex: 0 0 49%; flex: 0 0 49%;
width: 50%; width: 50%;
padding: 0.5em; padding: 0.5em;
/* margin: .1em; */ /* margin: .1em; */
margin-left: .1em; margin-left: 0.1em;
border: solid; border: solid;
border-color: var(--highlight-color); border-color: var(--highlight-color);
/* border-radius: .5em; */ /* border-radius: .5em; */
} }
#markdown_input { #markdown_input {
grid-column: 1; grid-column: 1;
grid-row: 1; grid-row: 1;
text-align: left; text-align: left;
color: var(--text-color); color: var(--text-color);
background: var(--main-bg-color); background: var(--main-bg-color);
overflow-x: wrap; overflow-x: wrap;
overflow-y: scroll; overflow-y: scroll;
} }
#rendered_markdown { #rendered_markdown {
grid-column: 2; grid-column: 2;
grid-row: 1; grid-row: 1;
text-align: left; text-align: left;
color: var(--text-color); color: var(--text-color);
background-color: var(--main-bg-color); background-color: var(--main-bg-color);
img { img {
width: 100%; width: 100%;
} }
overflow-x: wrap; overflow-x: wrap;
overflow-y: scroll; overflow-y: scroll;
} }
h1 { h1 {
text-align: left; text-align: left;
line-height: 18px; line-height: 18px;
margin-top: 0.067em; margin-top: 0.067em;
margin-bottom: 0.067em; margin-bottom: 0.067em;
color: red; color: red;
} }
li { li {
/* line-height: 0.1em; */ /* line-height: 0.1em; */
margin: 0; margin: 0;
margin-left: 1em; margin-left: 1em;
padding: 0; padding: 0;
} }
.sidebar_button { .sidebar_button {
width: 100%; width: 100%;
background-color: var(--main-bg-color); background-color: var(--main-bg-color);
border: none; border: none;
} }
.sidebar_icon { .sidebar_icon {
width: 100%; width: 100%;
} }
.top-bar { .top-bar {
display: flex;
display: flex; flex-direction: row;
flex-direction: row;
} }
.topbar_button { .topbar_button {
height: 2em; height: 2em;
background-color: transparent; background-color: transparent;
border: none; border: none;
} }
.topbar_icon { .topbar_icon {
height: 100%; height: 100%;
background-color: transparent; background-color: transparent;
} }
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
:root { :root {
color: #f6f6f6; color: #f6f6f6;
background-color: var(--main-bg-color); background-color: var(--main-bg-color);
} }
} }
.main { .main {
display: flex; display: flex;
height: 95vh; height: 95vh;
flex-direction: column; flex-direction: column;
} }
#sidebar { #sidebar {
visibility: visible; visibility: visible;
width: var(--sidebar-width); width: var(--sidebar-width);
transition: all 0.1s ease-out; transition: all 0.1s ease-out;
float: left; float: left;
} }
.filetree { .filetree {
float: left; float: left;
border: solid; border: solid;
border-color: var(--highlight-color); border-color: var(--highlight-color);
width: var(--filetree-width); width: var(--filetree-width);
overflow-x: scroll; overflow-x: scroll;
/* overflow-y: scroll; */ /* overflow-y: scroll; */
overflow-y: hidden; overflow-y: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
resize: horizontal; resize: horizontal;
} }
.filetree-directory-button, .filetree-directory-button,
.filetree-file-button, .filetree-file-button,
.file-search-button { .file-search-button {
background-color: transparent; background-color: transparent;
border: none; border: none;
width: 100%; width: 100%;
height: inherit; height: inherit;
text-align: left; text-align: left;
transition: all 0.01s ease-out; transition: all 0.01s ease-out;
white-space: nowrap; white-space: nowrap;
/* overflow-y: visible; */ /* overflow-y: visible; */
overflow-y: hidden; overflow-y: hidden;
overflow: hidden; overflow: hidden;
color: var(--text-color); color: var(--text-color);
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.filetree-node { .filetree-node {
margin-left: 1em; margin-left: 1em;
overflow-y: hidden; overflow-y: hidden;
} }
.filetree-icon { .filetree-icon {
height: 1em; height: 1em;
background-color: transparent; background-color: transparent;
margin-right: 5px; margin-right: 5px;
} }
.filetree_expand { .filetree_expand {
background-color: transparent; background-color: transparent;
border: none; border: none;
} }
.filetree-file-button:hover, .filetree-file-button:hover,
.filetree-directory-button:hover { .filetree-directory-button:hover {
background-color: var(--highlight-color); background-color: var(--highlight-color);
/* Green */ /* Green */
} }
dialog { dialog {
position: absolute; position: absolute;
top: 50%; top: 50%;
left: 50%; left: 50%;
transform: translate(-50%, -50%) !important; transform: translate(-50%, -50%) !important;
background-color: var(--highlight-color); background-color: var(--highlight-color);
border: none; border: none;
border-radius: 10px; border-radius: 10px;
box-shadow: 0 0 #0000, 0 0 #0000, 0 25px 50px -12px rgba(0, 0, 0, 0.25); box-shadow:
width: 50%; 0 0 #0000,
height: 20%; 0 0 #0000,
margin: auto; 0 25px 50px -12px rgba(0, 0, 0, 0.25);
/* display: flex; */ width: 50%;
/* flex-direction: column; */ height: 20%;
overflow: hidden; margin: auto;
color: var(--text-color); /* display: flex; */
font-size: .5cm; /* flex-direction: column; */
overflow: hidden;
color: var(--text-color);
font-size: 0.5cm;
} }
.row { .row {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
} }
.button { .button {
background-color: var(--accent-color); background-color: var(--accent-color);
/* Green */ /* Green */
color: white; color: white;
border: solid; border: solid;
border-color: transparent; border-color: transparent;
padding: 5px 3px; padding: 5px 3px;
text-align: center; text-align: center;
text-decoration: none; text-decoration: none;
display: inline-block; display: inline-block;
font-size: 16px; font-size: 16px;
} }
.button:hover { .button:hover {
border: solid;
border: solid; border-color: var(--bright-highlight-color);
border-color: var(--bright-highlight-color);
} }
.button:active { .button:active {
border: solid; border: solid;
border-color: white; border-color: white;
} }
.input-field { .input-field {
border: solid; border: solid;
border-color: var(--accent-color); border-color: var(--accent-color);
color: var(--text-color); color: var(--text-color);
} }
#knowledgebase-button { #knowledgebase-button {
width: 19%; width: 19%;
} }
#knowledgebase-path { #knowledgebase-path {
width: 80%; width: 80%;
} }
#file-search-dialog-input { #file-search-dialog-input {
border-top-right-radius: 10px; border-top-right-radius: 10px;
border-top-left-radius: 10px; border-top-left-radius: 10px;
} }
#file-search-results { #file-search-results {
overflow: scroll; overflow: scroll;
grid-column: 1; grid-column: 1;
grid-row: 1; grid-row: 1;
} }