use rand::seq::SliceRandom; use sauron::html::attributes::{class, id}; use sauron::html::events::on_click; use sauron::html::{div, text}; use sauron::prelude::*; use sauron::{Cmd, Component, Node, Program}; mod tlds; pub enum Msg { Click, ReceivedWords(Result, JsValue>), } pub struct App { output: Option, words: Vec, } impl App { pub fn new() -> Self { App { output: None, words: vec![], } } fn generate_domain(&mut self) -> String { let mut domain: String = String::from(""); while domain.is_empty() { let tld = self.get_random_tld(); tld.map(|tld| { let word = self.get_random_word(&tld); if word.is_some() { let mut word = word.unwrap(); word.truncate(word.len() - 2); domain = format!("{}.{}", word, tld); } }); } domain } fn get_random_tld(&mut self) -> Option { crate::tlds::tlds() .choose(&mut rand::thread_rng()) .map(|v| String::from(v)) } fn get_random_word(&self, tld: &str) -> Option { self.words .clone() .into_iter() .filter(|word| word.ends_with(tld)) .collect::>() .choose(&mut rand::thread_rng()) .map(|v| v.to_string().to_lowercase()) } } impl Component for App { fn init(&self) -> Cmd { Http::fetch_with_text_response_decoder( "/words.txt", |r: String| r.lines().map(|l| l.to_string()).collect(), Msg::ReceivedWords, ) } fn view(&self) -> Node { let output = match &self.output { Some(s) => vec![text(s)], None => vec![], }; let loading = self.words.len() == 0; sauron::html::main( vec![], vec![div( vec![class("container")], vec![ h1(vec![class("heading")], vec![text("Domain Hack Generator")]), div( vec![class("button-container")], vec![ button( vec![ class("button"), disabled(loading), on_click(|_: MouseEvent| Msg::Click), ], vec![text(if loading { "Loading..." } else { "Generate" })], ), p( vec![ id("result"), class(if output.is_empty() { "empty" } else { "" }), ], output, ), ], ), ], )], ) } fn update(&mut self, msg: Msg) -> Cmd { match msg { Msg::Click => self.output = Some(self.generate_domain()), Msg::ReceivedWords(result) => match result { Ok(words) => self.words = words, Err(_) => {} }, } Cmd::none() } } #[wasm_bindgen(start)] pub fn main() { console_log::init_with_level(log::Level::Trace).unwrap(); console_error_panic_hook::set_once(); Program::mount_to_body(App::new()); }