diff --git a/src/base.rs b/src/base.rs index 4a4f45a..79335b8 100644 --- a/src/base.rs +++ b/src/base.rs @@ -2,8 +2,8 @@ use leptos::{component, create_signal, view, For, IntoView, SignalGet}; use std::collections::VecDeque; mod banner; -mod prompt; use banner::Banner; +mod prompt; use prompt::Prompt; #[component] diff --git a/src/base/prompt.rs b/src/base/prompt.rs index 6eef93c..8f00f7f 100644 --- a/src/base/prompt.rs +++ b/src/base/prompt.rs @@ -1,15 +1,20 @@ -use leptos::ev::{keydown, KeyboardEvent, SubmitEvent}; +use leptos::ev::SubmitEvent; use leptos::html::{Form, Input}; use leptos::{ component, create_effect, create_node_ref, create_signal, spawn_local, view, IntoView, NodeRef, - ReadSignal, SignalGetUntracked, SignalUpdate, WriteSignal, + ReadSignal, WriteSignal, }; use leptos_use::{ - use_color_mode_with_options, use_cycle_list_with_options, use_event_listener, ColorMode, - UseColorModeOptions, UseColorModeReturn, UseCycleListOptions, UseCycleListReturn, + use_color_mode_with_options, use_cycle_list_with_options, ColorMode, UseColorModeOptions, + UseColorModeReturn, UseCycleListOptions, UseCycleListReturn, }; use std::collections::VecDeque; +mod general; +use general::general_commands; +mod keyboard; +use keyboard::keyboard_commands; + #[component] pub fn Prompt( submitter: WriteSignal, @@ -18,12 +23,21 @@ pub fn Prompt( ) -> impl IntoView { //Output and history index signals let (out, set_out) = create_signal(String::new()); - let (history_index, set_history_index) = create_signal(0); + let (history_index, set_history_index): (ReadSignal, WriteSignal) = create_signal(0); //Form and input elements let form_element: NodeRef
= create_node_ref(); let input_element: NodeRef = create_node_ref(); + // Focus on the new prompt on mount + create_effect(move |_| { + if let Some(ref_input) = input_element.get() { + let _ = ref_input.on_mount(|input| { + let _ = input.focus(); + }); + } + }); + //Themes let UseColorModeReturn { mode, set_mode, .. } = use_color_mode_with_options( UseColorModeOptions::default() @@ -48,108 +62,21 @@ pub fn Prompt( let next = next.clone(); spawn_local(async move { - let value = value.trim().replace("<", "‹").replace(">", "›"); - let val = value.split_once(' ').unwrap_or((&value, "")); - - match val.0 { - "clear" => { - submitter.update(|prompts| { - *prompts = 0; - }); - } - "history" => { - let hist: Vec = history.get_untracked().into(); - let hist: Vec = hist - .iter() - .rev() - .enumerate() - .map(|(i, c)| format!("{} {}", i + 1, c)) - .collect(); - set_out(hist.join("\n")); - } - "theme" | "t" | "wal" => { - next(); - let new_theme = state.get_untracked(); - set_out(format!( - r#"Theme changed to: {new_theme}"# - )); - } - _ => set_out(termfolio::Command::process(val.0, val.1).await), - } - - updater.update(|hist| { - if !value.is_empty() && hist.front() != Some(&value) { - hist.push_front(value); - if hist.len() > 20 { - hist.pop_back(); - } - } - }); - - submitter.update(|prompts| { - if *prompts < u8::MAX { - *prompts += 1; - } - }); + general_commands(value, state, next, set_out, submitter, updater, history).await }); form_element().unwrap().set_inert(true); input_element().unwrap().set_inert(true); }; - // Focus on the new prompt on mount - create_effect(move |_| { - if let Some(ref_input) = input_element.get() { - let _ = ref_input.on_mount(|input| { - let _ = input.focus(); - }); - } - }); - // Event listener for Up and Down arrow keys, Tab and Ctrl/Command + L - let _ = use_event_listener(input_element, keydown, move |ev: KeyboardEvent| { - let index = history_index.get_untracked(); - let hist = history.get_untracked(); - let inp = input_element.get_untracked().unwrap(); - - match &ev.key()[..] { - //Previous command in history - "ArrowUp" => { - ev.prevent_default(); - if index < hist.len() { - inp.set_value(&hist[index]); - set_history_index.update(|history_index| *history_index += 1); - } - } - //Next command in history - "ArrowDown" => { - if index > 1 { - inp.set_value(&hist[index - 2]); - set_history_index.update(|history_index| *history_index -= 1); - } else if index != 0 { - inp.set_value(""); - set_history_index.update(|history_index| *history_index -= 1); - } - } - //Autocomplete - "Tab" => { - ev.prevent_default(); - inp.set_value(termfolio::autocomplete(&inp.value())); - } - _ => {} - } - - //Clear - if (ev.ctrl_key() || ev.meta_key()) && (ev.key() == "l" || ev.key() == "L") { - ev.prevent_default(); - submitter.update(|prompts| { - *prompts = 0; - }); - submitter.update(|prompts| { - *prompts += 1; - }); - } - }); + keyboard_commands( + input_element, + history, + history_index, + set_history_index, + submitter, + ); view! { ( + value: String, + state: Signal, + next: F, + set_out: WriteSignal, + submitter: WriteSignal, + updater: WriteSignal>, + history: ReadSignal>, +) where + F: Fn(), +{ + let value = value.trim().replace("<", "‹").replace(">", "›"); + let val = value.split_once(' ').unwrap_or((&value, "")); + + match val.0 { + "clear" => { + submitter.update(|prompts| { + *prompts = 0; + }); + } + "history" => { + let hist: Vec = history.get_untracked().into(); + let hist: Vec = hist + .iter() + .rev() + .enumerate() + .map(|(i, c)| format!("{} {}", i + 1, c)) + .collect(); + set_out(hist.join("\n")); + } + "theme" | "t" | "wal" => { + next(); + let new_theme = state.get_untracked(); + set_out(format!( + r#"Theme changed to: {new_theme}"# + )); + } + _ => set_out(termfolio::Command::process(val.0, val.1).await), + } + + updater.update(|hist| { + if !value.is_empty() && hist.front() != Some(&value) { + hist.push_front(value); + if hist.len() > 20 { + hist.pop_back(); + } + } + }); + + submitter.update(|prompts| { + if *prompts < u8::MAX { + *prompts += 1; + } + }); +} diff --git a/src/base/prompt/keyboard.rs b/src/base/prompt/keyboard.rs new file mode 100644 index 0000000..d744747 --- /dev/null +++ b/src/base/prompt/keyboard.rs @@ -0,0 +1,57 @@ +use leptos::ev::{keydown, KeyboardEvent}; +use leptos::html::Input; +use leptos::{NodeRef, ReadSignal, SignalGetUntracked, SignalUpdate, WriteSignal}; +use leptos_use::use_event_listener; +use std::collections::VecDeque; + +pub fn keyboard_commands( + input_element: NodeRef, + history: ReadSignal>, + history_index: ReadSignal, + set_history_index: WriteSignal, + submitter: WriteSignal, +) { + let _ = use_event_listener(input_element, keydown, move |ev: KeyboardEvent| { + let index = history_index.get_untracked().into(); + let hist = history.get_untracked(); + let inp = input_element.get_untracked().unwrap(); + + match &ev.key()[..] { + //Previous command in history + "ArrowUp" => { + ev.prevent_default(); + if index < hist.len() { + inp.set_value(&hist[index]); + set_history_index.update(|history_index| *history_index += 1); + } + } + //Next command in history + "ArrowDown" => { + if index > 1 { + inp.set_value(&hist[index - 2]); + set_history_index.update(|history_index| *history_index -= 1); + } else if index == 1 { + inp.set_value(""); + set_history_index.update(|history_index| *history_index -= 1); + } + } + //Autocomplete + "Tab" => { + ev.prevent_default(); + inp.set_value(termfolio::autocomplete(&inp.value())); + } + _ => {} + } + + //Clear + if (ev.ctrl_key() || ev.meta_key()) && (ev.key() == "l" || ev.key() == "L") { + ev.prevent_default(); + submitter.update(|prompts| { + *prompts = 0; + }); + submitter.update(|prompts| { + *prompts += 1; + }); + } + }); +} diff --git a/src/fetch.rs b/src/fetch.rs index 323bea9..8e8348a 100644 --- a/src/fetch.rs +++ b/src/fetch.rs @@ -7,7 +7,8 @@ mod formats; use crate::texts::{FETCH_GITHUB_ERROR, READ_JSON_ERROR}; use formats::*; -// Config +// Config JSON + const JSON: &str = include_str!("../configs/config.json"); // Once statics diff --git a/src/texts.rs b/src/texts.rs index 2bd361b..f03854d 100644 --- a/src/texts.rs +++ b/src/texts.rs @@ -22,21 +22,25 @@ pub const CREDITS: &str = r#" _____ ______________ _________ | | | |___| |\ \| | | || | \ \_/ / |_____| |_\ \_/ / \_/ \____/\_| \_\_| |_/\_| \___/\_____/\___/ \___/ -Terminal style portfolio website, made using Rust. +Terminal style portfolio website, made in Leptos, Rust. Made by Sachith C Shetty Github: github.com/shettysach + Repo: github.com/shettysach/termfolio APIs used - + * Github REST API + * Pinned repos - Ysn4Irix/gh-pinned-repos-api + *