diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 014a7e8..6df005b 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -501,9 +501,9 @@ dependencies = [ [[package]] name = "dalet" -version = "1.0.0-pre2" +version = "1.0.0-pre3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a4c96bc370794e34c34ed93abe3f04140b9909bc80b942b98a9abd7b8c248d" +checksum = "c629ef0fc95fddd843a73e72de3f509665a73f51323f7b6c1b7946eb8937b660" dependencies = [ "serde", ] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index cf414ad..f036481 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -25,7 +25,7 @@ tauri = { version = "1", features = [ ] } serde = { version = "1", features = ["derive"] } serde_json = "1" -dalet = "1.0.0-pre2" +dalet = "1.0.0-pre3" reqwest = "0.12.5" [features] diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 88acdeb..7867cd7 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -1,118 +1,79 @@ // Prevents additional console window on Windows in release, DO NOT REMOVE!! #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] -use std::{ - fs::{self}, - sync::Mutex, -}; - -use dalet::{Argument, Body, Tag}; +use std::fs::{self}; mod types; mod utils; -use tauri::Manager; -use types::{TabType, VigiError, VigiState}; +use tauri::async_runtime::Mutex; +use types::{VigiError, VigiJsState, VigiState}; use utils::{read_or_create_jsonl, read_or_create_number}; // Learn more about Tauri commands at https://tauri.app/v1/guides/features/command #[tauri::command] -async fn process_input( +async fn update_input( input: String, state: tauri::State<'_, Mutex>, -) -> Result, VigiError> { - // TODO: Implement mime type, language, protocol or search detection - // TODO: Implement text links parsing - - println!("Processing: {}", input); - - match reqwest::get(input.clone()).await { - Ok(res) => match res.text().await { - Ok(res) => { - update_tab(state, TabType::Text, res.clone(), input.clone())?; - Ok(vec![Tag::new(0, Body::Text(res), Argument::Null)]) - } - Err(_) => Err(VigiError::Parse), - }, - Err(_) => Err(VigiError::Network), - } -} - -#[tauri::command] -fn get_state(state: tauri::State>) -> VigiState { - (*state.lock().unwrap()).clone() -} - -#[tauri::command] -fn select_tab(state: tauri::State>, index: usize) -> Result<(), VigiError> { - match state.lock() { - Ok(mut state) => { - state.update_current_tab_index(index)?; - Ok(()) - } - Err(_) => Err(VigiError::StateLock), - } -} - -#[tauri::command] -fn add_tab(state: tauri::State>) -> Result<(), VigiError> { - match state.lock() { - Ok(mut state) => { - state.add_tab()?; - Ok(()) - } - Err(_) => Err(VigiError::StateLock), - } -} - -#[tauri::command] -fn remove_tab(state: tauri::State>, index: usize) -> Result<(), VigiError> { - match state.lock() { - Ok(mut state) => { - state.remove_tab(index)?; - Ok(()) - } - Err(_) => Err(VigiError::StateLock), - } -} - -fn update_tab( - state: tauri::State>, - tab_type: TabType, - tab_title: String, - tab_url: String, ) -> Result<(), VigiError> { - match state.lock() { - Ok(mut state) => { - state.update_tab(tab_type, tab_title, tab_url)?; - Ok(()) - } - Err(_) => Err(VigiError::StateLock), - } + state.lock().await.update_input(input).await +} + +#[tauri::command] +async fn get_js_state(state: tauri::State<'_, Mutex>) -> Result { + Ok(state.lock().await.get_js_state()) +} + +#[tauri::command] +async fn select_tab( + index: usize, + state: tauri::State<'_, Mutex>, +) -> Result<(), VigiError> { + state.lock().await.select_tab(index).await +} + +#[tauri::command] +async fn load_tab(state: tauri::State<'_, Mutex>) -> Result<(), VigiError> { + state.lock().await.load_tab().await +} + +#[tauri::command] +async fn add_tab(state: tauri::State<'_, Mutex>) -> Result<(), VigiError> { + state.lock().await.add_tab() +} + +#[tauri::command] +async fn remove_tab( + state: tauri::State<'_, Mutex>, + index: usize, +) -> Result<(), VigiError> { + state.lock().await.remove_tab(index) } fn main() { tauri::Builder::default() .manage(Mutex::new(VigiState::null())) - .setup(setup_handler) .invoke_handler(tauri::generate_handler![ - process_input, - get_state, + update_input, + get_js_state, select_tab, + load_tab, add_tab, - remove_tab + remove_tab, + setup ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); } -fn setup_handler(app: &mut tauri::App) -> Result<(), Box> { +#[tauri::command] +async fn setup( + state: tauri::State<'_, Mutex>, + app_handle: tauri::AppHandle, +) -> Result<(), VigiError> { println!("---Setup---"); - let app_handle = app.handle(); - - let state = app.state::>(); - let mut state = state.lock().unwrap(); + let mut state = state.lock().await; let config_dir = app_handle .path_resolver() @@ -138,7 +99,7 @@ fn setup_handler(app: &mut tauri::App) -> Result<(), Box Result<(), Box Result<(), Box, pub favorites_tabs: Vec, + + // Temporary + pub top_bar_input: String, + pub current_data: Vec, +} + +#[derive(Serialize, Debug, Clone)] +pub struct VigiJsState { + pub current_tab_index: usize, + pub tabs: Vec, + pub favorites_tabs: Vec, + + pub top_bar_input: String, + pub current_data: Vec, } impl VigiState { @@ -39,16 +57,24 @@ impl VigiState { current_tab_index: 0, tabs: Vec::new(), favorites_tabs: Vec::new(), + + top_bar_input: "".to_string(), + current_data: Vec::new(), } } - pub fn update_current_tab_index(&mut self, new_index: usize) -> Result<(), VigiError> { + pub async fn select_tab(&mut self, new_index: usize) -> Result<(), VigiError> { self.current_tab_index = new_index; - self.write_current_tab_index()?; + + self.update_top_bar_input(); Ok(()) } + pub fn update_top_bar_input(&mut self) { + self.top_bar_input = self.tabs[self.current_tab_index].url.clone(); + } + fn write_current_tab_index(&mut self) -> Result<(), VigiError> { fs::write( &self.current_tab_index_path, @@ -62,7 +88,61 @@ impl VigiState { .map_err(|_| VigiError::StateUpdate) } - pub fn update_tab( + async fn process_input(&mut self) -> Result<(), VigiError> { + // TODO: Implement mime type, language, protocol or search detection + // TODO: Implement text links parsing + + println!("process_input {{\n \"{}\"", self.top_bar_input); + + let result = match self.top_bar_input.as_str() { + "" => { + self.update_tab(TabType::HomePage, "Home".to_owned(), "".to_owned())?; + + self.current_data = vec![Tag::new( + 0, + Body::Text("Type something in the address bar".to_owned()), + Argument::Null, + )]; + + Ok(()) + } + input => match reqwest::get(input).await { + Ok(res) => match res.text().await { + Ok(res) => { + let mut truncated = res.clone(); + truncated.truncate(50); + + self.update_tab(TabType::Text, truncated, input.to_owned())?; + + self.current_data = vec![Tag::new(0, Body::Text(res), Argument::Null)]; + + Ok(()) + } + Err(_) => Err(VigiError::Parse), + }, + Err(_) => Err(VigiError::Network), + }, + }; + + if result.is_ok() { + println!(" Ok\n}}"); + } else { + println!(" Err\n}}"); + } + + result + } + + pub async fn update_input(&mut self, input: String) -> Result<(), VigiError> { + self.top_bar_input = input; + self.process_input().await + } + + pub async fn load_tab(&mut self) -> Result<(), VigiError> { + self.process_input().await + } + + fn update_tab( &mut self, tab_type: TabType, tab_title: String, @@ -84,7 +164,7 @@ impl VigiState { self.tabs_id_counter += 1; self.tabs.push(Tab::new( TabType::HomePage, - "New tab".to_string(), + "Home".to_string(), "".to_string(), self.tabs_id_counter, )); @@ -95,6 +175,8 @@ impl VigiState { self.current_tab_index = self.tabs.len() - 1; self.write_current_tab_index()?; + self.update_top_bar_input(); + Ok(()) } @@ -112,14 +194,25 @@ impl VigiState { Ok(()) } + + pub fn get_js_state(&self) -> VigiJsState { + VigiJsState { + current_tab_index: self.current_tab_index, + tabs: self.tabs.clone(), + favorites_tabs: self.favorites_tabs.clone(), + + top_bar_input: self.top_bar_input.clone(), + current_data: self.current_data.clone(), + } + } } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct Tab { - ty: TabType, - title: String, - url: String, - id: usize, + pub ty: TabType, + pub title: String, + pub url: String, + pub id: usize, } impl Tab { diff --git a/src/app.css b/src/app.css index 169d6b0..16c1def 100644 --- a/src/app.css +++ b/src/app.css @@ -11,7 +11,7 @@ } body { - @apply bg-vigi-90 text-vigi-10; + @apply bg-vigi-90 text-vigi-10 cursor-default; user-select: none; } @@ -31,7 +31,7 @@ body { } .browser-window { - @apply grow shadow-inner overflow-auto select-text; + @apply grow shadow-inner overflow-auto select-text cursor-auto; } .window-controls { @@ -48,7 +48,7 @@ body { @apply active:bg-vigi-100; } -.open-tabs { +.tabs-category { @apply flex justify-between mt-2 mx-2; } diff --git a/src/lib/components/BrowserWindow.svelte b/src/lib/components/BrowserWindow.svelte index b7c3390..2107966 100644 --- a/src/lib/components/BrowserWindow.svelte +++ b/src/lib/components/BrowserWindow.svelte @@ -2,13 +2,24 @@ import type { Root } from "@txtdot/dalet"; import Block from "./Block.svelte"; import Renderer from "./DaletlRenderer/Renderer.svelte"; + import { isLoading, state } from "$lib/stores"; + import type { VigiState } from "$lib/types"; - export let data: Root; - export let isLoading = false; + let loading = false; + + let data: Root; + + state.subscribe((st) => { + data = (st as VigiState).current_data; + }); + + isLoading.subscribe((val) => { + loading = val; + }); - {#if isLoading} + {#if loading}
Loading...
{:else} diff --git a/src/lib/components/Sidebar.svelte b/src/lib/components/Sidebar.svelte index 03194c3..861fcd8 100644 --- a/src/lib/components/Sidebar.svelte +++ b/src/lib/components/Sidebar.svelte @@ -29,7 +29,7 @@ {#if collapsed} -
+
Open tabs - + { if (e.key === "Enter") { - topBarInput.set(currentInput); - onInput(); + updateInput(currentInput); } }} on:focus={() => { diff --git a/src/lib/stores.ts b/src/lib/stores.ts index 47384e8..538ea93 100644 --- a/src/lib/stores.ts +++ b/src/lib/stores.ts @@ -1,6 +1,12 @@ import { writable, type Writable } from "svelte/store"; import type { VigiState } from "./types"; -export const topBarInput: Writable = writable(""); +export const state: Writable = writable({ + current_tab_index: 0, + tabs: [{ id: 0, ty: "HomePage", title: "Home", url: "" }], + favorites_tabs: [], + top_bar_input: "", + current_data: [], +}); -export const state: Writable = writable(); +export const isLoading: Writable = writable(false); diff --git a/src/lib/types.ts b/src/lib/types.ts index 43a8eac..57fbb5c 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -1,7 +1,12 @@ +import type { Tag } from "@txtdot/dalet"; + export interface VigiState { current_tab_index: number; tabs: StateTab[]; favorites_tabs: StateTab[]; + + top_bar_input: string; + current_data: Tag[]; } type TabType = "HomePage" | "Text"; diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 2114c5b..0119513 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -1,32 +1,52 @@ import { invoke } from "@tauri-apps/api"; -import { state, topBarInput } from "./stores"; -import type { StateTab, VigiState } from "./types"; +import { isLoading, state } from "./stores"; +import type { VigiState } from "./types"; -export function updateVigiState() { - invoke("get_state") - .then((r) => { - let st = r as VigiState; +export async function updateVigiState() { + try { + let st = await invoke("get_js_state"); + state.set(st as VigiState); + } catch (e) { + console.log(e); + } +} - state.set(st); +export async function updateInput(input: string) { + isLoading.set(true); - topBarInput.set(st.tabs[st.current_tab_index].url); - }) - .catch((err) => console.log(err)); + try { + await invoke("update_input", { input }); + } catch (e) { + console.log(e); + } finally { + await updateVigiState(); + isLoading.set(false); + } } export async function addTab() { await invoke("add_tab"); - - updateVigiState(); + await updateVigiState(); + await loadTab(); } export async function selectTab(index: number) { await invoke("select_tab", { index }); - - updateVigiState(); + await updateVigiState(); + await loadTab(); } export async function removeTab(index: number) { await invoke("remove_tab", { index }); - updateVigiState(); + await updateVigiState(); + await loadTab(); +} + +export async function loadTab() { + isLoading.set(true); + + await invoke("load_tab"); + await updateVigiState(); + + isLoading.set(false); } diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index cba7e5f..6dd869c 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -4,43 +4,31 @@ import TopBar from "$lib/components/TopBar.svelte"; import Sidebar from "$lib/components/Sidebar.svelte"; import BrowserWindow from "$lib/components/BrowserWindow.svelte"; - import type { Root } from "@txtdot/dalet"; import { invoke } from "@tauri-apps/api/tauri"; - import { topBarInput } from "$lib/stores"; - import { updateVigiState } from "$lib/utils"; + import { loadTab, updateVigiState } from "$lib/utils"; + import { isLoading } from "$lib/stores"; let sidebarOpen = true; - let isLoading = false; - - let data: Root = []; - - updateVigiState(); + (async () => { + isLoading.set(true); + await invoke("setup"); + await updateVigiState(); + await loadTab(); + isLoading.set(false); + })(); document.addEventListener("keypress", (e: KeyboardEvent) => { - const formElements = ["INPUT", "TEXTAREA", "SELECT", "OPTION"]; - if (formElements.includes((e.target as Element).tagName)) { + if ( + ["INPUT", "TEXTAREA", "SELECT", "OPTION"].includes( + (e.target as Element).tagName + ) + ) { return; } if (e.key === "q") sidebarOpen = !sidebarOpen; }); - - topBarInput.subscribe((input) => { - isLoading = true; - invoke("process_input", { input }) - .then((res) => { - data = res as Root; - isLoading = false; - }) - .catch((err) => { - data = [{ id: 0, body: "Error: " + err, argument: null }]; - isLoading = false; - }) - .finally(() => { - updateVigiState(); - }); - });
- +