diff --git a/.gitignore b/.gitignore old mode 100755 new mode 100644 index 53bf3e9..344684b --- a/.gitignore +++ b/.gitignore @@ -1,18 +1,13 @@ -/tailwind -/target/ +target/ *.iml Cargo.lock -/.idea/ -/.vscode/ -/frontend/.idea/ -/frontend/target/ -/frontend/node_modules/ -/frontend/dist/ -/frontend/img/lottie.js -/frontend/css/output.css -/frontend/package-lock.json -/frontend/Cargo.lock -src-tauri/target/ -src-tauri/Cargo.lock -src-tauri/.idea/ +.vscode/ +target/ +node_modules/ +dist/ +lottie.js +output.css +package-lock.json +target/ +.idea/ src-tauri/icons diff --git a/Cargo.toml b/Cargo.toml old mode 100755 new mode 100644 index 48b5992..382931e --- a/Cargo.toml +++ b/Cargo.toml @@ -2,37 +2,28 @@ members = ["src-tauri", "frontend", "ubi-crates/*"] [workspace.package] -version = "0.0.1" +version = "0.2.0" authors = ["Stephen Power"] description = "A cross-platform markdown editor." license = "GPL" edition = "2021" -rust-version = "1.60" [profile.release] panic = "abort" codegen-units = 1 lto = true opt-level = "z" -# strip = true [workspace.dependencies] ron = "0.8" - serde = { version = "1.0.154", features = ["derive"] } log = { version = "0.4", features = ["release_max_level_info"] } walkdir = "2.3.2" thiserror = "1.0.38" dirs = "5.0.0" -toml = "0.7.2" -figment = { version = "0.10.8", features = ["toml"] } -yew = { version = "0.20.0", features = ["csr"] } -gloo = "0.8" -web-sys = { version = "0.3.35", features=["Navigator", "HtmlButtonElement", "HtmlDivElement", "Event", "EventTarget", "MouseEvent", "InputEvent"]} -wasm-bindgen = "0.2.84" getrandom = { version = "0.2.8", features = ["js"] } markdown = "1.0.0-alpha.7" urlencoding = "2.1.2" -rfd = "0.11.3" config = { path = "./ubi-crates/config" } -error = { path = "./ubi-crates/error" } \ No newline at end of file +error = { path = "./ubi-crates/error" } +md = { path = "./ubi-crates/md" } \ No newline at end of file diff --git a/README.md b/README.md old mode 100755 new mode 100644 diff --git a/build.sh b/build.sh old mode 100755 new mode 100644 diff --git a/frontend/Cargo.toml b/frontend/Cargo.toml old mode 100755 new mode 100644 index 02d3c1c..ee3e0d9 --- a/frontend/Cargo.toml +++ b/frontend/Cargo.toml @@ -3,21 +3,15 @@ name = "frontend" version = "0.0.1" edition = "2021" -[profile.release] -panic = "abort" -codegen-units = 1 -lto = true -opt-level = "z" -# strip = true - [features] +web = [] desktop = [] +mobile = [] [dev-dependencies] -wasm-bindgen-test = "0.2" +wasm-bindgen-test = "0.3.36" [dependencies] -time = { version = "0.3.15", features = ["wasm-bindgen"] } serde_json = "1.0.96" serde = { workspace = true } @@ -25,28 +19,36 @@ log = { workspace = true } walkdir = { workspace = true } thiserror = { workspace = true } dirs = { workspace = true } -toml = { workspace = true } -figment = { workspace = true } -web-sys = { workspace = true } config = { workspace = true } error = { workspace = true } +md = { workspace = true } + + +web-sys = { version = "0.3.63", features=["DataTransfer", "Element", "Navigator", "HtmlAnchorElement", "HtmlButtonElement", "HtmlDialogElement", "Navigator", "Clipboard", +"HtmlDivElement", "HtmlDocument", "HtmlInputElement", "HtmlLabelElement", "HtmlTextAreaElement", "Event", "EventTarget", "MouseEvent", "InputEvent", "KeyEvent", "KeyboardEvent", "KeyboardEventInit", +"TouchEvent", "TouchList", "Touch", "DomTokenList"]} +wasm-bindgen = "=0.2.86" +wasm-bindgen-cli = "=0.2.86" +wasm-bindgen-futures = "=0.4.36" +js-sys = "0.3.63" +serde-wasm-bindgen = "0.5.0" + +yew = { version = "0.20.0", features = ["csr"] } +gloo = "0.8" +gloo-timers = "0.2.6" -yew = { workspace = true } -gloo = { workspace = true } -wasm-bindgen = { workspace = true } -wasm-bindgen-futures = "0.4.34" getrandom = { workspace = true } markdown = { workspace = true } urlencoding = { workspace = true } -rfd="0.10" - tauri-sys = { git = "https://github.com/bicarlsen/tauri-sys.git", branch = "fs", features = [ "all", ] } undo = "0.49.0" +regex = "1.8.4" +lazy_static = "1.4.0" wasm-logger = "0.2.0" -yew-router = "0.17.0" \ No newline at end of file +yew-router = "0.17.0" diff --git a/frontend/Trunk.toml b/frontend/Trunk.toml new file mode 100644 index 0000000..a31d0f8 --- /dev/null +++ b/frontend/Trunk.toml @@ -0,0 +1,101 @@ +# An example Trunk.toml with all possible fields along with their defaults. + +[build] +# The index HTML file to drive the bundling process. +# target = "index.desktop.html" +# Build in release mode. +release = true +# The output dir for all final assets. +dist = "dist" +# The public URL from which assets are to be served. +public_url = "/" +# Whether to include hash values in the output file names. +filehash = true + +[watch] +# Paths to watch. The `build.target`'s parent folder is watched by default. +watch = [] +# Paths to ignore. +ignore = [] + +[serve] +# The address to serve on. +address = "127.0.0.1" +# The port to serve on. +port = 8080 +# Open a browser tab once the initial build is complete. +open = false +# Disable auto-reload of the web app. +no_autoreload = false + +[clean] +# The output dir for all final assets. +dist = "dist" +# Optionally perform a cargo clean. +cargo = false + +[tools] +# Default dart-sass version to download. +sass = "1.54.9" +# Default wasm-bindgen version to download. +wasm_bindgen = "0.2.86" +# Default wasm-opt version to download. +wasm_opt = "version_110" + +## proxy +# Proxies are optional, and default to `None`. +# Proxies are only run as part of the `trunk serve` command. + +[[proxy]] +# This WebSocket proxy example has a backend and ws field. This example will listen for +# WebSocket connections at `/api/ws` and proxy them to `ws://localhost:9000/api/ws`. +backend = "ws://localhost:9000/api/ws" +ws = true + +[[proxy]] +# This proxy example has a backend and a rewrite field. Requests received on `rewrite` will be +# proxied to the backend after rewriting the `rewrite` prefix to the `backend`'s URI prefix. +# E.G., `/api/v1/resource/x/y/z` -> `/resource/x/y/z` +rewrite = "/api/v1/" +backend = "http://localhost:9000/" + +[[proxy]] +# This proxy specifies only the backend, which is the only required field. In this example, +# request URIs are not modified when proxied. +backend = "http://localhost:9000/api/v2/" + +[[proxy]] +# This proxy example has an insecure field. In this example, +# connections to https://localhost:9000/api/v3/ will not have certificate validation performed. +# This is useful for development with a server using self-signed certificates. +backend = "https://localhost:9000/api/v3/" +insecure = true + +## hooks +# Hooks are optional, and default to `None`. +# Hooks are executed as part of Trunk's main build pipeline, no matter how it is run. + +# [[hooks]] +# # This hook example shows all the current available fields. It will execute the equivalent of +# # typing "echo Hello Trunk!" right at the start of the build process (even before the HTML file +# # is read). By default, the command is spawned directly and no shell is used. +# stage = "pre_build" +# command = "echo" +# command_arguments = ["Hello", "Trunk!"] + +# [[hooks]] +# # This hook example shows running a command inside a shell. As a result, features such as variable +# # interpolation are available. This shows the TRUNK_STAGING_DIR environment variable, one of a set +# # of default variables that Trunk inserts into your hook's environment. Additionally, this hook +# # uses the build stage, meaning it executes in parallel with all of the existing asset pipelines. +# # stage = "build" +# # command = "sh" +# # command_arguments = ["-c", "echo Staging directory: $TRUNK_STAGING_DIR"] + +# [[hooks]] +# # This hook example shows how command_arguments defaults to an empty list when absent. It also uses +# # the post_build stage, meaning it executes after the rest of the build is complete, just before +# # the staging directory is copied over the dist directory. This means that it has access to all +# # built assets, including the HTML file generated by trunk. +# stage = "post_build" +# command = "ls" \ No newline at end of file diff --git a/frontend/css/fonts.css b/frontend/css/fonts.css old mode 100755 new mode 100644 index 4a4b3c2..e9f3c3f --- a/frontend/css/fonts.css +++ b/frontend/css/fonts.css @@ -1,10 +1,14 @@ @font-face { font-family: "Comfortaa"; src: local(Comfortaa), url("../fonts/comfortaa.woff2"); +} +@font-face { + font-family: "Fira Mono"; + src: local(Fira Mono), url("../fonts/fira.woff2"); } @font-face { - font-family: "Inconsolata"; - src: local(Inconsolata), url("../fonts/inconsolata.woff2"); + font-family: "Inter"; + src: local(Inter) } \ No newline at end of file diff --git a/frontend/css/input.css b/frontend/css/input.css old mode 100755 new mode 100644 diff --git a/frontend/css/scrollbar.css b/frontend/css/scrollbar.css old mode 100755 new mode 100644 diff --git a/frontend/css/textarea.css b/frontend/css/textarea.css old mode 100755 new mode 100644 diff --git a/frontend/fonts/comfortaa.woff2 b/frontend/fonts/comfortaa.woff2 old mode 100755 new mode 100644 diff --git a/frontend/fonts/fira.woff2 b/frontend/fonts/fira.woff2 new file mode 100644 index 0000000..04e3fad Binary files /dev/null and b/frontend/fonts/fira.woff2 differ diff --git a/frontend/fonts/inconsolata.woff2 b/frontend/fonts/inconsolata.woff2 deleted file mode 100755 index 3a228c0..0000000 Binary files a/frontend/fonts/inconsolata.woff2 and /dev/null differ diff --git a/frontend/img/404.json b/frontend/img/404.json old mode 100755 new mode 100644 diff --git a/frontend/img/btc.svg b/frontend/img/btc.svg new file mode 100644 index 0000000..6dc9d58 --- /dev/null +++ b/frontend/img/btc.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/img/xmr.svg b/frontend/img/xmr.svg new file mode 100644 index 0000000..ae15da0 --- /dev/null +++ b/frontend/img/xmr.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/index_web.html b/frontend/index.android.html old mode 100755 new mode 100644 similarity index 55% rename from frontend/index_web.html rename to frontend/index.android.html index ca25068..5af27c2 --- a/frontend/index_web.html +++ b/frontend/index.android.html @@ -3,12 +3,7 @@ - + Ubiquity @@ -16,7 +11,7 @@ - + \ No newline at end of file diff --git a/frontend/index.desktop.html b/frontend/index.desktop.html new file mode 100644 index 0000000..57348e3 --- /dev/null +++ b/frontend/index.desktop.html @@ -0,0 +1,17 @@ + + + + + + + Ubiquity + + + + + + + + + + \ No newline at end of file diff --git a/frontend/index_desktop.html b/frontend/index.web.html old mode 100755 new mode 100644 similarity index 65% rename from frontend/index_desktop.html rename to frontend/index.web.html index 5383e51..baff859 --- a/frontend/index_desktop.html +++ b/frontend/index.web.html @@ -5,10 +5,8 @@ + content="default-src blob: data: filesystem: ws: wss: http: https: tauri: 'wasm-unsafe-eval' 'self'; script-src blob: data: filesystem: ws: wss: http: https: tauri: 'wasm-unsafe-eval' 'self'" /> + Ubiquity @@ -16,7 +14,7 @@ - + \ No newline at end of file diff --git a/frontend/package.json b/frontend/package.json old mode 100755 new mode 100644 index d621836..4fbb494 --- a/frontend/package.json +++ b/frontend/package.json @@ -6,6 +6,11 @@ "devDependencies": { "@tailwindcss/typography": "^0.5.9", "daisyui": "^2.50.0", + "internal-ip": "^7.0.0", "tailwindcss": "^3.2.4" + }, + "dependencies": { + "@tauri-apps/api": "^2.0.0-alpha.4", + "@tauri-apps/cli": "^2.0.0-alpha.9" } } \ No newline at end of file diff --git a/frontend/src/components/btn.rs b/frontend/src/components/btn.rs new file mode 100644 index 0000000..66dc81d --- /dev/null +++ b/frontend/src/components/btn.rs @@ -0,0 +1,117 @@ +use yew::prelude::*; + +#[derive(Debug, PartialEq, Properties)] +pub struct BtnProps { + pub onclick: Callback, + pub size: BtnSize, + pub style: BtnStyle, + pub outline: bool, + pub children: Children +} + +#[derive(Debug, PartialEq)] +pub enum BtnSize { + VerySmall, + Small, + Normal, + Large +} + +#[derive(Debug, PartialEq)] +pub enum BtnShape { + Normal, + Wide, + Block, + Circle +} + +#[derive(Debug, PartialEq)] +pub enum BtnWidth { + Normal, + Wide, + Full +} + +#[derive(Debug, PartialEq)] +pub enum BtnStyle { + Ghost, + Normal, + Neutral, + Primary, + Secondary, + Accent, + Info, + Success, + Error, +} + + + +#[derive(Debug, PartialEq)] +pub enum Color { + Base100, + Base200, + Base300, + Ghost, + Normal, + Neutral, + NeutralFocus, + NeutralContent, + Primary, + PrimaryFocus, + PrimaryContent, + Secondary, + SecondaryFocus, + SecondaryContent, + Accent, + AccentFocus, + AccentContent, + Info, + InfoFocus, + InfoContent, + Success, + SuccessFocus, + SuccessContent, + Error, + ErrorFocus, + ErrorContent, +} + +#[function_component(Btn)] +pub fn btn(props: &BtnProps) -> Html { + // let btn_size = match props.size { + // BtnSize::VerySmall => "btn-xs", + // BtnSize::Small => "btn-sm", + // BtnSize::Normal => "", + // BtnSize::Large => "btn-lg", + // }; + + let btn_style = match props.style { + BtnStyle::Normal => "", + BtnStyle::Neutral => "btn-neutral", + BtnStyle::Primary => "btn-primary-content", + BtnStyle::Secondary => "btn-secondary", + BtnStyle::Accent => "btn-accent", + BtnStyle::Info => "btn-info", + BtnStyle::Success => "btn-success", + BtnStyle::Error => "btn-error", + BtnStyle::Ghost => "btn-ghost", + }; + + let mut container_classes = classes!( + btn_style, + "xs:btn-xs", + "sm:btn-sm", + "lg:btn-lg", + ); + + if props.outline { + container_classes.push("btn-outline") + } + + html! { + + } +} \ No newline at end of file diff --git a/frontend/src/components/container.rs b/frontend/src/components/container.rs old mode 100755 new mode 100644 index e97838b..debdf78 --- a/frontend/src/components/container.rs +++ b/frontend/src/components/container.rs @@ -1,5 +1,7 @@ use yew::prelude::*; +use crate::contexts::config::use_config; + #[derive(Debug, PartialEq, Properties)] pub struct ContainerProps { pub children: Children, @@ -7,8 +9,28 @@ pub struct ContainerProps { #[function_component(Container)] pub fn container(props: &ContainerProps) -> Html { + + let mut container_classes = classes!( + "my-auto", + "border-2", + "border-base-content", + "rounded-xl", + "p-4", + "pb-8", + "2xl:w-[65%]", + "xl:w-[72.5%]", + "lg:w-[80%]", + "md:w-[87.5%]", + "sm-[95%]", + "w-[98%]" + ); + + match use_config().is_mobile_ui() { + true => container_classes.push("h-[calc(100dvh-6.5rem)]"), + false => container_classes.push("h-[calc(100dvh-7.25rem)]"), + } html! { -
+
{ props.children.clone() }
} diff --git a/frontend/src/components/divider.rs b/frontend/src/components/divider.rs old mode 100755 new mode 100644 index 5aa9a5f..9e41233 --- a/frontend/src/components/divider.rs +++ b/frontend/src/components/divider.rs @@ -1,8 +1,15 @@ use yew::prelude::*; -#[function_component(Divider)] -pub fn divider() -> Html { +#[function_component(DividerYAxis)] +pub fn divider_y_axis() -> Html { html! { -
+
} } + +#[function_component(DividerXAxis)] +pub fn divider_x_axis() -> Html { + html! { +
+ } +} \ No newline at end of file diff --git a/frontend/src/components/drawer.rs b/frontend/src/components/drawer.rs new file mode 100644 index 0000000..6b20b89 --- /dev/null +++ b/frontend/src/components/drawer.rs @@ -0,0 +1,108 @@ +use yew::prelude::*; +use yew_router::prelude::use_navigator; + +use crate::{contexts::config::use_config, pages::Page}; + +#[derive(Debug, PartialEq, Properties)] +pub struct DrawerProps { + pub children: Children, +} + + +#[function_component(Drawer)] +pub fn drawer(props: &DrawerProps) -> Html { + let theme = use_config().state().theme; + + let drawer_classes = classes!( + "flex", + "flex-col", + "h-full", + "bg-base-300", + "py-2", + "3xl:w-[10%]", + "2xl:w-[15%]", + "xl:w-[20%]", + "lg:w-[30%]", + "md:w-[40%]", + "sm:w-[50%]", + "xs:w-[60%]", + "w-[60%]", + ); + + html! { +
+ +
+ { props.children.clone() } +
+
+ +
+

{"Ubiquity"}

+
+ +
+
+
+
+ } +} + +#[function_component(Home)] +pub fn home() -> Html { + let nav = use_navigator().unwrap(); + let home = Callback::from(move |_| {nav.replace(&Page::Home)}); + + html! { +
  • +
    + + + + {"Home"} +
    +
  • + } +} + +#[function_component(Settings)] +pub fn home() -> Html { + let nav = use_navigator().unwrap(); + let settings = Callback::from(move |_| {nav.push(&Page::Settings)}); + + html! { +
  • +
    + + + + {"Settings"} +
    +
  • + } +} + +#[function_component(About)] +pub fn about() -> Html { + let nav = use_navigator().unwrap(); + let about = Callback::from(move |_| {nav.push(&Page::About)}); + + html! { +
  • +
    + + + + + + {"About"} +
    +
  • + } +} \ No newline at end of file diff --git a/frontend/src/components/dual_view.rs b/frontend/src/components/dual_view.rs old mode 100755 new mode 100644 index bf68249..48734a0 --- a/frontend/src/components/dual_view.rs +++ b/frontend/src/components/dual_view.rs @@ -5,10 +5,21 @@ use crate::components::markdown_preview::MarkdownPreview; #[function_component(DualView)] pub fn dual_view() -> Html { + let dual_view_classes = classes!( + "w-[calc(100vw-2.5rem)]", + "flex", + "flex-1", + "flex-row", + "justify-center", + "space-x-8", + "items-center", + "h-[calc(100vh-8.5rem)]" + ); + html! { -
    +
    - + diff --git a/frontend/src/components/footer.rs b/frontend/src/components/footer.rs new file mode 100644 index 0000000..54548a9 --- /dev/null +++ b/frontend/src/components/footer.rs @@ -0,0 +1,64 @@ +use config::View; +use yew::prelude::*; + +use crate::{icons::{PreviewDisabledIcon, PreviewEnabledIcon}, contexts::config::use_config}; + +#[function_component(Footer)] +pub fn footer() -> Html { + let config = use_config(); + let config_clone = config.clone(); + + let swap_to_preview = Callback::from(move |_| { + config.set_view(View::Preview); + }); + + let swap_to_editor = Callback::from(move |_| { + config_clone.set_view(View::Input); + }); + + let footer_classes = classes!( + "flex", + "flex-row", + "min-w-screen", + "py-2", + "bg-base-300", + ); + + let footer_section_classes = classes!( + "flex", + "flex-col", + "w-[50vw]", + "items-center", + "self-center" + ); + + let footer_item_classes = classes!( + "focus:neutral-focus", + "flex", + "flex-col", + "items-center" + ); + + let footer_item_text_classes = classes!( + "font-sans", + "text-xs", + "text-center" + ); + + html! { +
    +
    +
    + +

    {"Editor"}

    +
    +
    +
    +
    + +

    {"Preview"}

    +
    +
    +
    + } +} \ No newline at end of file diff --git a/frontend/src/components/header/add_dropdown.rs b/frontend/src/components/header/add_dropdown.rs new file mode 100644 index 0000000..21034bc --- /dev/null +++ b/frontend/src/components/header/add_dropdown.rs @@ -0,0 +1,223 @@ +use std::path::PathBuf; + +use error::UbiquityError; +use gloo::console::debug; +use yew::prelude::*; +use crate::contexts::config::use_config; +use crate::contexts::markdown::{use_markdown}; +use crate::components::{header::Markdown, tooltip::Tooltip}; +use crate::icons::AddFileIcon; +use crate::tauri::read_markdown_from_fs; +use crate::components::toasts::{display_toast, display_toast_error}; +use web_sys::{HtmlInputElement, HtmlDivElement, HtmlLabelElement}; +use gloo::{utils::document, file::{Blob, futures::read_as_text}}; +use wasm_bindgen_futures::spawn_local; +use wasm_bindgen::JsCast; +use urlencoding::encode; +use serde::{Deserialize, Serialize}; +use md::*; + + +#[function_component(AddFileDropdown)] +pub fn add_file_dropdown() -> Html { + let markdown_ctx = use_markdown(); + + let mut recent_files_html: Vec = Vec::new(); + let recent_files = Markdown::read_all_markdown_keys(); + recent_files.iter().for_each(|recent_file| { + let file_name = recent_file.clone(); + let markdown_ctx = markdown_ctx.clone(); + + + let read_file = Callback::from(move |_| { + if cfg!(feature = "web") { + let md = Markdown::load_from_storage(file_name.clone()); + markdown_ctx.set_markdown(md); + } else { + let markdown_ctx = markdown_ctx.clone(); + + let file_name = file_name.clone(); + spawn_local(async move { + let key = file_name.clone(); + let path = file_name.clone().to_string(); + let read_file: Result = read_markdown_from_fs(key.clone()).await; + + match read_file { + Ok(file) => { + let text = AttrValue::from(file); + let key = Some(key); + let md = Markdown::from(text, key); + markdown_ctx.add_markdown(md.clone()); + markdown_ctx.set_markdown(md); + }, + Err(error) => { + display_toast_error(error); + } + } + }); + } + }); + + let file_name = recent_file.clone(); + let html = html! { +
  • + +
    + {file_name} +
    +
    +
  • + }; + recent_files_html.push(html); + }); + + let is_mobile_ui = use_config().is_mobile_ui(); + + let mut dropdown_classes = classes!("dropdown"); + + match is_mobile_ui { + true => dropdown_classes.push("dropdown-end"), + false => dropdown_classes.push("dropdown-hover"), + } + + let icon_size = match is_mobile_ui { + true => AttrValue::from("24"), + false => AttrValue::from("32"), + }; + + html! { +
    + + +
    + } +} + +#[cfg(feature = "web")] +#[function_component(CreateFileBtn)] +pub fn create_file_btn() -> Html { + let markdown_ctx = use_markdown(); + + let open_modal = Callback::from(move |_| { + let input: HtmlInputElement = document().get_element_by_id("create-file").unwrap().dyn_into().unwrap(); + input.set_checked(true); + }); + + html! { +
  • +
    + {"Create File"} +
    +
  • + } +} + +#[cfg(not(feature = "web"))] +#[function_component(CreateFileBtn)] +pub fn create_file_btn() -> Html { + use crate::tauri::{self, save_markdown_to_fs, create_new_markdown_file}; + + let markdown_ctx = use_markdown(); + + let create = Callback::from(move |_| { + let markdown = markdown_ctx.state(); + let markdown_ctx_clone = markdown_ctx.clone(); + spawn_local(async move { + let save: Result = create_new_markdown_file().await; + match save { + Ok(key) => { + let md = Markdown::from(AttrValue::from(""), Some(AttrValue::from(key))); + markdown_ctx_clone.add_markdown(md.clone()); + markdown_ctx_clone.set_markdown(md.clone()); + }, + Err(error) => { display_toast_error(error) } + } + }); + }); + + html! { +
  • +
    + {"Create File"} +
    +
  • + } +} + +#[cfg(feature = "web")] +#[function_component(AddFileBtn)] +pub fn add_file_btn() -> Html { + let markdown_ctx = use_markdown(); + + let onfileupload = Callback::from(move |e: Event| { + let markdown_ctx = markdown_ctx.clone(); + let input: HtmlInputElement = e.target_unchecked_into(); + let filelist = input.files().unwrap(); + let file = filelist.get(0).unwrap(); + let key = Some(AttrValue::from(file.name())); + let blob: Blob = file.into(); + + spawn_local(async move { + let file_str = read_as_text(&blob).await.unwrap(); + let text = AttrValue::from(file_str); + let markdown = Markdown { key, text }; + markdown_ctx.add_markdown(markdown); + }); + }); + + html! { +
  • + + +
  • + } +} + +#[cfg(not(feature = "web"))] +#[function_component(AddFileBtn)] +pub fn add_file_btn() -> Html { + use crate::tauri::{create_new_markdown_file, import_markdown_file}; + + let markdown = use_markdown().state(); + let encoded_md = encode(&markdown.text).to_string(); + + let mut text_dl = String::from("data:attachment/text,"); + text_dl.push_str(&encoded_md); + + let ctx = use_markdown(); + let read_from_fs = Callback::from(move |_| { + let ctx = ctx.clone(); + spawn_local(async move { + let create_file: Result = import_markdown_file().await; + match create_file { + Ok(markdown) => { + ctx.add_markdown(markdown); + }, + Err(error) => {}// display_toast_error(error) + } + }); + }); + + html! { +
  • +
    + {"Import File"} +
    +
  • + } +} \ No newline at end of file diff --git a/frontend/src/components/header.rs b/frontend/src/components/header/mod.rs old mode 100755 new mode 100644 similarity index 50% rename from frontend/src/components/header.rs rename to frontend/src/components/header/mod.rs index 6f8e2d4..5331e07 --- a/frontend/src/components/header.rs +++ b/frontend/src/components/header/mod.rs @@ -1,32 +1,57 @@ -use web_sys::HtmlInputElement; +pub mod save_btn; +pub mod add_dropdown; + +use wasm_bindgen::JsCast; +use web_sys::{HtmlInputElement, HtmlLabelElement, HtmlDivElement, KeyboardEventInit, HtmlDocument}; use yew::prelude::*; use yew_router::prelude::use_navigator; -use gloo::file::{Blob, futures::read_as_text}; +use gloo::{file::{Blob, futures::read_as_text}, utils::{document, window}}; use urlencoding::encode; use crate::{ - components::{divider::Divider, theme_card::ThemeDropdownItem, tooltip::Tooltip}, - icons::{AddFileIcon, RedoIcon, UndoIcon, SaveIcon}, - Page, contexts::{markdown::{use_markdown, Markdown}}, + components::{divider::DividerYAxis, theme_card::ThemeDropdownItem, tooltip::Tooltip, header::{save_btn::SaveBtn, add_dropdown::AddFileDropdown}}, + icons::{AddFileIcon, RedoIcon, UndoIcon, SaveIcon, HamburgerIcon, WrenchIcon}, + Page, contexts::{markdown::{use_markdown, Markdown}, config::use_config}, }; use wasm_bindgen_futures::spawn_local; #[function_component(Header)] pub fn header() -> Html { - let nav_0 = use_navigator().unwrap(); - let nav_1 = nav_0.clone(); - let nav_2 = nav_1.clone(); + let mobile_ui = use_config().is_mobile_ui(); + + html! { + if mobile_ui { + + } else { + + } + } +} - let home_cb= Callback::from(move |_| nav_0.push(&Page::Home)); - let settings_cb = Callback::from(move |_| nav_1.push(&Page::Settings)); - let about_cb = Callback::from(move |_| nav_2.push(&Page::About)); +#[function_component(DesktopHeader)] +pub fn desktop_header() -> Html { + let nav = use_navigator().unwrap(); + let home_cb= Callback::from(move |_| nav.replace(&Page::Home)); + + let nav = use_navigator().unwrap(); + let settings_cb = Callback::from(move |_| nav.push(&Page::Settings)); + + let nav = use_navigator().unwrap(); + let about_cb = Callback::from(move |_| nav.push(&Page::About)); + + let markdown = use_markdown().state(); + let encoded_md = encode(&markdown.text).to_string(); + + let mut text_dl = String::from("data:attachment/text,"); + text_dl.push_str(&encoded_md); + + let download_name = use_markdown().state().key; html! {