From 15c43e348271f499679880ed41196bba50f6cb42 Mon Sep 17 00:00:00 2001 From: Artemy Egorov Date: Sun, 4 Aug 2024 00:06:12 +0300 Subject: [PATCH] fix: refactor request system, sidebar animation, placeholder color transition --- src-tauri/Cargo.lock | 219 +++++++++++++++++++- src-tauri/Cargo.toml | 27 ++- src-tauri/src/main.rs | 1 + src-tauri/src/process_input/mod.rs | 25 +++ src-tauri/src/process_input/process_data.rs | 25 +++ src-tauri/src/process_input/process_url.rs | 52 +++++ src-tauri/src/types.rs | 43 ++-- src/app.css | 16 +- src/lib/components/Sidebar.svelte | 27 ++- 9 files changed, 372 insertions(+), 63 deletions(-) create mode 100644 src-tauri/src/process_input/mod.rs create mode 100644 src-tauri/src/process_input/process_data.rs create mode 100644 src-tauri/src/process_input/process_url.rs diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 784faf5..62a45f5 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -56,6 +56,55 @@ dependencies = [ "libc", ] +[[package]] +name = "anstream" +version = "0.6.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" + +[[package]] +name = "anstyle-parse" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + [[package]] name = "anyhow" version = "1.0.86" @@ -255,6 +304,10 @@ name = "cc" version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f" +dependencies = [ + "jobserver", + "libc", +] [[package]] name = "cesu8" @@ -311,6 +364,46 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "clap" +version = "4.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fbb260a053428790f3de475e304ff84cdbc4face759ea7a3e64c1edd938a7fc" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64b17d7ea74e9f833c7dbf2cbe4fb12ff26783eda4782a8975b72f895c9b4d99" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "clap_lex" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" + [[package]] name = "cocoa" version = "0.24.1" @@ -347,6 +440,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" +[[package]] +name = "colorchoice" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" + [[package]] name = "combine" version = "4.6.7" @@ -504,11 +603,16 @@ dependencies = [ [[package]] name = "dalet" -version = "1.0.0-pre3" +version = "1.0.0-pre6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c629ef0fc95fddd843a73e72de3f509665a73f51323f7b6c1b7946eb8937b660" +checksum = "8bc4c347533f8341633bd820799dea680f600e50891310b74bc914740681e8c2" dependencies = [ + "clap", + "enum-procs", + "num_enum 0.7.3", "serde", + "serde_repr", + "zstd", ] [[package]] @@ -656,6 +760,16 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "enum-procs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e188616f4527e2cf6128e58622bb2fd16ebcfa37a200b2d16739c3ca227bf649" +dependencies = [ + "quote", + "syn 2.0.72", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -1541,6 +1655,12 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itoa" version = "0.4.8" @@ -1596,6 +1716,15 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + [[package]] name = "js-sys" version = "0.3.69" @@ -1807,7 +1936,7 @@ dependencies = [ "bitflags 1.3.2", "jni-sys", "ndk-sys", - "num_enum", + "num_enum 0.5.11", "thiserror", ] @@ -1869,7 +1998,16 @@ version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" dependencies = [ - "num_enum_derive", + "num_enum_derive 0.5.11", +] + +[[package]] +name = "num_enum" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +dependencies = [ + "num_enum_derive 0.7.3", ] [[package]] @@ -1884,6 +2022,18 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "num_enum_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.72", +] + [[package]] name = "objc" version = "0.2.7" @@ -2660,6 +2810,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" dependencies = [ "once_cell", + "ring", "rustls-pki-types", "rustls-webpki", "subtle", @@ -3539,6 +3690,20 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "tokio-gemini" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5aea8fd82d63287b051d76b86e0497105564cb8fa269d43bf369a2d1b93bb5d" +dependencies = [ + "mime", + "num_enum 0.7.3", + "tokio", + "tokio-rustls", + "url", + "webpki-roots", +] + [[package]] name = "tokio-native-tls" version = "0.3.1" @@ -3792,6 +3957,12 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "uuid" version = "1.10.0" @@ -3836,11 +4007,14 @@ name = "vigi" version = "0.0.0" dependencies = [ "dalet", + "mime", "reqwest 0.12.5", "serde", "serde_json", "tauri", "tauri-build", + "tokio-gemini", + "url", ] [[package]] @@ -4030,6 +4204,15 @@ dependencies = [ "system-deps 6.2.2", ] +[[package]] +name = "webpki-roots" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "webview2-com" version = "0.19.1" @@ -4565,3 +4748,31 @@ dependencies = [ "crc32fast", "crossbeam-utils", ] + +[[package]] +name = "zstd" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.13+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index c91512f..6473151 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -12,21 +12,26 @@ license = "AGPL-3.0" tauri-build = { version = "1", features = [] } [dependencies] -tauri = { version = "1", features = [ "updater", - "window-hide", - "window-start-dragging", - "window-close", - "window-minimize", - "window-show", - "window-unminimize", - "window-unmaximize", - "window-maximize", - "shell-open", +tauri = { version = "1", features = [ + "updater", + "window-hide", + "window-start-dragging", + "window-close", + "window-minimize", + "window-show", + "window-unminimize", + "window-unmaximize", + "window-maximize", + "shell-open", ] } serde = { version = "1", features = ["derive"] } serde_json = "1" -dalet = "1.0.0-pre3" +dalet = "1.0.0-pre6" + reqwest = "0.12.5" +tokio-gemini = "0.1.0" +url = "2.5.2" +mime = "0.3.17" [features] # This feature is used for production builds or when a dev server is not specified, DO NOT REMOVE!! diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 9967eff..64adb72 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -3,6 +3,7 @@ use std::fs::{self}; +mod process_input; mod types; mod utils; diff --git a/src-tauri/src/process_input/mod.rs b/src-tauri/src/process_input/mod.rs new file mode 100644 index 0000000..097f254 --- /dev/null +++ b/src-tauri/src/process_input/mod.rs @@ -0,0 +1,25 @@ +use crate::types::{VigiError, VigiOutput}; +use mime::Mime; +use url::Url; + +mod process_data; +mod process_url; + +use process_data::process_data; +use process_url::process_url; + +type Data = Vec; +type ReqResult = (Mime, Data); + +pub async fn process_input(input: &String) -> Result { + let parsed = Url::parse(input); + + let (mime, data) = match parsed { + Ok(url) => process_url(url).await?, + Err(_) => Err(VigiError::Network)?, + }; + + let result = process_data(mime, data).await?; + + Ok(result) +} diff --git a/src-tauri/src/process_input/process_data.rs b/src-tauri/src/process_input/process_data.rs new file mode 100644 index 0000000..86eefc8 --- /dev/null +++ b/src-tauri/src/process_input/process_data.rs @@ -0,0 +1,25 @@ +use dalet::{daletl::ToDaletlPage, typed::Tag::*}; +use mime::Mime; + +use crate::types::{VigiError, VigiOutput}; + +pub async fn process_data(mime: Mime, data: Vec) -> Result { + let result = match (mime.type_().as_str(), mime.subtype().as_str()) { + ("text", "plain") => { + process_text(String::from_utf8(data).map_err(|_| VigiError::TextIsNotUtf8)?).await + } + // ("text", "gemini") => { + // process_text(String::from_utf8(data).map_err(|_| VigiError::TextIsNotUtf8)?).await + // } + _ => Err(VigiError::UnsupportedMimeType)?, + }; + + Ok(result) +} + +async fn process_text(data: String) -> VigiOutput { + let mut truncated = data.clone(); + truncated.truncate(50); + + VigiOutput::new(truncated, vec![El(data.into())].to_dl_page()) +} diff --git a/src-tauri/src/process_input/process_url.rs b/src-tauri/src/process_input/process_url.rs new file mode 100644 index 0000000..f45c916 --- /dev/null +++ b/src-tauri/src/process_input/process_url.rs @@ -0,0 +1,52 @@ +use mime::Mime; +use reqwest::header::CONTENT_TYPE; +use url::Url; + +use crate::types::VigiError; + +use super::ReqResult; + +pub async fn process_url(url: Url) -> Result { + let result = match url.scheme() { + "http" | "https" => process_http(url.to_string()).await?, + // "gemini" => process_gemini(url.to_string()).await?, + _ => Err(VigiError::UnsupportedProtocol)?, + }; + + Ok(result) +} + +async fn process_http(url: String) -> Result { + let res = reqwest::get(&url).await.map_err(|_| VigiError::Network)?; + + let mime_type = { + match res.headers().get(CONTENT_TYPE) { + Some(header) => match header.to_str() { + Ok(mime) => mime.to_owned(), + Err(_) => "text/plain".to_owned(), + }, + None => "text/plain".to_owned(), + } + } + .parse::() + .map_err(|_| VigiError::InvalidMimeType)?; + + Ok(( + mime_type, + res.bytes().await.map_err(|_| VigiError::Network)?.into(), + )) +} + +// async fn process_gemini(url: String) -> Result { +// let res = tokio_gemini::Client::default() +// .request(&url) +// .await +// .map_err(|e| { +// println!("{:#?}", e); +// VigiError::Network +// })?; + +// let mime_type = res.mime().map_err(|_| VigiError::InvalidMimeType)?; + +// Ok((mime_type, res.message().as_bytes().into())) +// } diff --git a/src-tauri/src/types.rs b/src-tauri/src/types.rs index c8b4b8d..c65eaaa 100644 --- a/src-tauri/src/types.rs +++ b/src-tauri/src/types.rs @@ -1,9 +1,12 @@ -use dalet::{Argument, Body, Tag}; +use dalet::daletl::{Tag, ToDaletlPage}; +use dalet::typed::Tag::*; use serde::{Deserialize, Serialize}; use std::{collections::HashMap, fs, path::PathBuf}; use crate::utils::write_tabs; +use crate::process_input::process_input; + #[derive(Serialize, Deserialize, Debug)] pub enum VigiError { Network, @@ -13,9 +16,15 @@ pub enum VigiError { Filesystem, Config, GetTab, + + UnsupportedProtocol, + UnsupportedMimeType, + InvalidMimeType, + + TextIsNotUtf8, } -#[derive(Serialize, Debug, Clone)] +#[derive(Debug, Clone)] pub struct VigiState { pub tabs_id_counter_path: PathBuf, pub current_tab_index_path: PathBuf, @@ -36,7 +45,7 @@ pub struct VigiState { pub cached_inputs: HashMap, } -#[derive(Serialize, Debug, Clone)] +#[derive(Debug, Clone)] pub struct VigiOutput { pub title: String, pub data: Vec, @@ -113,9 +122,6 @@ impl VigiState { } async fn process_input(&mut self, ignore_cache: bool) -> Result<(), VigiError> { - // TODO: Implement mime type, language, protocol or search detection - // TODO: Implement text links parsing - println!("process_input \"{}\"", self.top_bar_input); let cached = !ignore_cache && self.cached_inputs.contains_key(&self.top_bar_input); @@ -123,34 +129,13 @@ impl VigiState { let output = { if cached { self.cached_inputs.get(&self.top_bar_input).unwrap().clone() - } else if self.top_bar_input.starts_with("https://") - || self.top_bar_input.starts_with("http://") - { - let res = reqwest::get(&self.top_bar_input) - .await - .map_err(|_| VigiError::Network)? - .text() - .await - .map_err(|_| VigiError::Network)?; - - let mut truncated = res.clone(); - truncated.truncate(50); - - VigiOutput::new( - truncated, - vec![Tag::new(0, Body::Text(res), Argument::Null)], - ) } else if self.top_bar_input.is_empty() { VigiOutput::new( "Homepage".to_owned(), - vec![Tag::new( - 0, - Body::Text("Type something in the address bar".to_owned()), - Argument::Null, - )], + vec![El("Type something in the address bar".into())].to_dl_page(), ) } else { - Err(VigiError::Parse)? + process_input(&self.top_bar_input).await? } }; diff --git a/src/app.css b/src/app.css index 7cffd15..bf2cf2e 100644 --- a/src/app.css +++ b/src/app.css @@ -68,6 +68,11 @@ body { @apply flex justify-between mt-2 mx-2; } +.tabs-category-text { + @apply overflow-hidden; + white-space: nowrap; +} + .block { @apply p-2 rounded-xl color-vigi-60; } @@ -76,18 +81,18 @@ body { @apply shrink-0 grow-0 flex flex-col w-1/5; @apply ease-out duration-300; - @apply max-sm:hidden; + @apply max-md:hidden; } .sidebar.collapsed { - @apply basis-0; + @apply basis-0 w-0; @apply p-0 m-0; @apply overflow-hidden; } .top-bar { - @apply flex max-sm:flex-row-reverse gap-3; + @apply flex max-md:flex-row-reverse gap-3; } .top-bar-buttons { @@ -97,11 +102,11 @@ body { .hide-sidebar-button, .back-button, .forward-button { - @apply max-sm:hidden; + @apply max-md:hidden; } .open-tabs-page-button { - @apply sm:hidden; + @apply md:hidden; } .search-input { @@ -116,6 +121,7 @@ body { input::placeholder { @apply color-vigi-60; @apply focus:color-vigi-50 hover:color-vigi-55; + @apply ease-out duration-100; } .tabs { diff --git a/src/lib/components/Sidebar.svelte b/src/lib/components/Sidebar.svelte index c2f8336..3ec1363 100644 --- a/src/lib/components/Sidebar.svelte +++ b/src/lib/components/Sidebar.svelte @@ -7,6 +7,7 @@ import { addTab } from "$lib/utils"; import Button from "./Button.svelte"; import Add from "$lib/icons/Add.svelte"; + import { fade } from "svelte/transition"; export let collapsed = true; @@ -24,20 +25,18 @@ - {#if collapsed} - + -
- Open tabs - -
+
+
Open tabs
+ +
-
- {#each tabs as tab, i (tab.id)} - - {/each} -
- {/if} +
+ {#each tabs as tab, i (tab.id)} + + {/each} +