Compare commits
	
		
			No commits in common. "d521d69eac53c9ab1cfc6bacf258e73c8e537b1a" and "1fbef7644bff3341313b6f984a56e97ab9fdecc7" have entirely different histories. 
		
	
	
		
			d521d69eac
			...
			1fbef7644b
		
	
		| 
						 | 
				
			
			@ -1,5 +1 @@
 | 
			
		|||
/target
 | 
			
		||||
 | 
			
		||||
/dist
 | 
			
		||||
 | 
			
		||||
/.idea
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
				
			
			@ -13,5 +13,4 @@ log = "0.4.20"
 | 
			
		|||
rand = { version = "0.8.5", default-features = false, features = ["alloc"] }
 | 
			
		||||
wasm-bindgen = "0.2.87"
 | 
			
		||||
wasm-logger = "0.2.0"
 | 
			
		||||
web-sys = "0.3.64"
 | 
			
		||||
yew = { version = "0.20.0", features = ["csr"] }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,9 +3,7 @@
 | 
			
		|||
<head>
 | 
			
		||||
    <meta charset="UTF-8">
 | 
			
		||||
    <title>Yew App</title>
 | 
			
		||||
    <link rel="stylesheet" href="https://maxst.icons8.com/vue-static/landings/line-awesome/line-awesome/1.3.0/css/line-awesome.min.css">
 | 
			
		||||
    <link data-trunk rel="css" href="static/css/styles.css" />
 | 
			
		||||
    <link data-trunk rel="css" href="static/css/normalize.css" />
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
<h1>Hola mundo</h1>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,26 +1,18 @@
 | 
			
		|||
use crate::consts::{AttemptField, Status};
 | 
			
		||||
use yew::prelude::*;
 | 
			
		||||
 | 
			
		||||
#[derive(Properties, PartialEq)]
 | 
			
		||||
pub struct AttemptRowProps {
 | 
			
		||||
    pub attempt: Vec<AttemptField>,
 | 
			
		||||
    pub answer: AttrValue,
 | 
			
		||||
    pub text: AttrValue,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[function_component]
 | 
			
		||||
pub fn AttemptRow(props: &AttemptRowProps) -> Html {
 | 
			
		||||
    let AttemptRowProps { attempt } = props;
 | 
			
		||||
    let AttemptRowProps { answer, text } = props;
 | 
			
		||||
 | 
			
		||||
    html! {
 | 
			
		||||
        { for attempt.iter().map(|att| html_nested! {
 | 
			
		||||
            <p
 | 
			
		||||
                class={
 | 
			
		||||
                    match att.status {
 | 
			
		||||
                        Status::Found => "correct",
 | 
			
		||||
                        Status::Almost => "almost",
 | 
			
		||||
                        Status::NotFound => "missed",
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            >{ att.char_field }</p>
 | 
			
		||||
        })}
 | 
			
		||||
        { for answer.chars().zip(text.chars()).map(|(ans, att)| html! { <p class={
 | 
			
		||||
            if ans == att { "correct" } else if answer.contains(att) { "almost" } else { "missed" }
 | 
			
		||||
        } >{ att }</p> }) }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,37 +0,0 @@
 | 
			
		|||
use yew::prelude::*;
 | 
			
		||||
use crate::components::{EmptyRow, CurrentRow, AttemptRow};
 | 
			
		||||
use crate::consts::{Attempts, MAX_ATTEMPTS};
 | 
			
		||||
 | 
			
		||||
#[derive(Properties, PartialEq)]
 | 
			
		||||
pub struct BoardProps {
 | 
			
		||||
    pub attempts: Attempts,
 | 
			
		||||
    pub attempt_index: usize,
 | 
			
		||||
    pub current_attempt: AttrValue,
 | 
			
		||||
    pub onkeypress: Callback<KeyboardEvent>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[function_component]
 | 
			
		||||
pub fn Board(props: &BoardProps) -> Html {
 | 
			
		||||
    let BoardProps {
 | 
			
		||||
        attempts,
 | 
			
		||||
        attempt_index,
 | 
			
		||||
        current_attempt,
 | 
			
		||||
        onkeypress
 | 
			
		||||
    } = props;
 | 
			
		||||
 | 
			
		||||
    html! {
 | 
			
		||||
        <div class="board" onkeyup={onkeypress} tabindex="0">
 | 
			
		||||
            {
 | 
			
		||||
                for (0..MAX_ATTEMPTS).map(|i| {
 | 
			
		||||
                    if i < *attempt_index {
 | 
			
		||||
                        html! { <AttemptRow attempt={ attempts.fields[i].clone() } /> }
 | 
			
		||||
                    } else if i == *attempt_index {
 | 
			
		||||
                        html! { <CurrentRow text={ current_attempt } /> }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        html! { <EmptyRow /> }
 | 
			
		||||
                    }
 | 
			
		||||
                })
 | 
			
		||||
            }
 | 
			
		||||
        </div>
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,31 +0,0 @@
 | 
			
		|||
use crate::consts::{Key, KeyboardKeyType, VirtualKey};
 | 
			
		||||
use yew::prelude::*;
 | 
			
		||||
 | 
			
		||||
#[derive(Properties, PartialEq)]
 | 
			
		||||
pub struct KeyboardProps {
 | 
			
		||||
    pub onclick: Callback<Key>,
 | 
			
		||||
    pub keyboard: UseStateHandle<Vec<VirtualKey>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[function_component]
 | 
			
		||||
pub fn Keyboard(props: &KeyboardProps) -> Html {
 | 
			
		||||
    let handle_click = |k: Key| {
 | 
			
		||||
        let onclick = props.onclick.clone();
 | 
			
		||||
 | 
			
		||||
        Callback::from(move |_| {
 | 
			
		||||
            onclick.emit(k);
 | 
			
		||||
        }).clone()
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    html! {
 | 
			
		||||
        <div class="keyboard"> {
 | 
			
		||||
            for (props.keyboard).iter().map(|vk: &VirtualKey| {
 | 
			
		||||
                match vk.key {
 | 
			
		||||
                    KeyboardKeyType::CharKey(c) => html! { <button onclick={ handle_click(Key::CharKey(c)) }> { c } </button> },
 | 
			
		||||
                    KeyboardKeyType::Backspace => html! { <button onclick={ handle_click(Key::Backspace) } class="key-big"><i class="las la-undo"></i></button> },
 | 
			
		||||
                    KeyboardKeyType::Enter => html! { <button onclick={ handle_click(Key::Enter) }  class="key-big"> { "Enviar" } </button> }
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
        } </div>
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,13 +1,9 @@
 | 
			
		|||
pub use crate::components::attempt_row::AttemptRow;
 | 
			
		||||
pub use crate::components::current_row::CurrentRow;
 | 
			
		||||
pub use crate::components::empty_row::EmptyRow;
 | 
			
		||||
pub use crate::components::keyboard::Keyboard;
 | 
			
		||||
pub use crate::components::result_board::ResultBoard;
 | 
			
		||||
pub use crate::components::board::Board;
 | 
			
		||||
 | 
			
		||||
mod board;
 | 
			
		||||
mod attempt_row;
 | 
			
		||||
mod current_row;
 | 
			
		||||
mod empty_row;
 | 
			
		||||
mod keyboard;
 | 
			
		||||
mod result_board;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,31 +1,33 @@
 | 
			
		|||
use crate::consts::GameResult;
 | 
			
		||||
use yew::prelude::*;
 | 
			
		||||
use crate::consts::{Attempts, Status};
 | 
			
		||||
 | 
			
		||||
#[derive(Properties, PartialEq)]
 | 
			
		||||
pub struct ResultBoardProps {
 | 
			
		||||
    pub attempts: Attempts,
 | 
			
		||||
    pub answer: AttrValue,
 | 
			
		||||
    pub attempts: Vec<String>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[function_component]
 | 
			
		||||
pub fn ResultBoard(props: &ResultBoardProps) -> Html {
 | 
			
		||||
    let ResultBoardProps {
 | 
			
		||||
        attempts,
 | 
			
		||||
    } = props;
 | 
			
		||||
    let ResultBoardProps { answer, attempts } = props;
 | 
			
		||||
    let answer_chars = answer.chars();
 | 
			
		||||
 | 
			
		||||
    let mut result = String::default();
 | 
			
		||||
 | 
			
		||||
    html! {
 | 
			
		||||
        <div class="result-board"> {
 | 
			
		||||
            for attempts.fields.iter().map(|attempt| {
 | 
			
		||||
                html_nested! {
 | 
			
		||||
                    <p class={ "result-board" }> {
 | 
			
		||||
                        for attempt.iter().map(| att| {
 | 
			
		||||
                            match att.status {
 | 
			
		||||
                                Status::Found => html_nested! { <> { "🟩" } </> },
 | 
			
		||||
                                Status::Almost => html_nested! { <span>{ "🟨" }</span> },
 | 
			
		||||
                                Status::NotFound => html_nested! { <span>{ "⬜" }</span> }
 | 
			
		||||
            for attempts.iter().map(|attempt| {
 | 
			
		||||
                html! {
 | 
			
		||||
                    <> {
 | 
			
		||||
                        for answer.chars().zip(attempt.chars()).map(| (ans, att)| {
 | 
			
		||||
                            if ans == att {
 | 
			
		||||
                                html! { <span> { "🟩" } </span> }
 | 
			
		||||
                            } else if answer.contains(att) {
 | 
			
		||||
                                html! { <span>{ "🟨" }</span> }
 | 
			
		||||
                            } else {
 | 
			
		||||
                                html! { <span>{ "⬜" }</span> }
 | 
			
		||||
                            }
 | 
			
		||||
                        })
 | 
			
		||||
                    } </p>
 | 
			
		||||
                    } </>
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
        } </div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,66 +1,10 @@
 | 
			
		|||
use yew::html::IntoPropValue;
 | 
			
		||||
 | 
			
		||||
pub const MAX_ATTEMPTS: usize = 6;
 | 
			
		||||
pub const WORD_LEN: usize = 5;
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, PartialEq)]
 | 
			
		||||
pub enum KeyboardKeyType {
 | 
			
		||||
    Enter,
 | 
			
		||||
    Backspace,
 | 
			
		||||
    CharKey(char),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, PartialEq)]
 | 
			
		||||
pub enum Status {
 | 
			
		||||
    NotFound,
 | 
			
		||||
    Found,
 | 
			
		||||
    Almost,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, PartialEq)]
 | 
			
		||||
pub struct AttemptField {
 | 
			
		||||
    pub char_field: char,
 | 
			
		||||
    pub status: Status,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, PartialEq)]
 | 
			
		||||
pub struct Attempts {
 | 
			
		||||
    pub fields: Vec<Vec<AttemptField>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Attempts {
 | 
			
		||||
    pub fn new() -> Self {
 | 
			
		||||
        Attempts {
 | 
			
		||||
            fields: vec![]
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, PartialEq)]
 | 
			
		||||
pub struct VirtualKey {
 | 
			
		||||
    pub key: KeyboardKeyType,
 | 
			
		||||
    pub status: Option<Status>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl VirtualKey {
 | 
			
		||||
    pub fn from_charkey(charkey: char) -> Self {
 | 
			
		||||
        VirtualKey {
 | 
			
		||||
            key: KeyboardKeyType::CharKey(charkey),
 | 
			
		||||
            status: None,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn from_key(key: KeyboardKeyType) -> Self {
 | 
			
		||||
        VirtualKey { key, status: None }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Copy, Clone)]
 | 
			
		||||
pub enum Key {
 | 
			
		||||
    // 13
 | 
			
		||||
    Enter,
 | 
			
		||||
    // 8
 | 
			
		||||
    // 13
 | 
			
		||||
    Backspace,
 | 
			
		||||
    // 8
 | 
			
		||||
    CharKey(char),
 | 
			
		||||
    Ignored,
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -77,8 +21,7 @@ impl From<u32> for Key {
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(PartialEq, Copy, Clone)]
 | 
			
		||||
pub enum GameResult {
 | 
			
		||||
pub enum Result {
 | 
			
		||||
    Win,
 | 
			
		||||
    Fail,
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +0,0 @@
 | 
			
		|||
pub use use_board::use_board;
 | 
			
		||||
pub use use_board::UseBoardHandle;
 | 
			
		||||
 | 
			
		||||
mod use_board;
 | 
			
		||||
| 
						 | 
				
			
			@ -1,114 +0,0 @@
 | 
			
		|||
use crate::consts::{AttemptField, Attempts, GameResult, Key, VirtualKey, MAX_ATTEMPTS};
 | 
			
		||||
use crate::services::words::{get_word_of_the_day, WORDS};
 | 
			
		||||
use crate::utils::{evaluate_status, new_empty_virtual_keyboard};
 | 
			
		||||
use std::cell::RefCell;
 | 
			
		||||
use std::rc::Rc;
 | 
			
		||||
use yew::prelude::*;
 | 
			
		||||
 | 
			
		||||
type AttemptRow = Attempts;
 | 
			
		||||
 | 
			
		||||
#[derive(PartialEq, Clone)]
 | 
			
		||||
pub struct UseBoardHandle {
 | 
			
		||||
    pub current_attempt: UseStateHandle<String>,
 | 
			
		||||
    pub attempts: UseStateHandle<AttemptRow>,
 | 
			
		||||
    pub virtual_keyboard: UseStateHandle<Vec<VirtualKey>>,
 | 
			
		||||
    pub result: UseStateHandle<Option<GameResult>>,
 | 
			
		||||
    pub attempt_index: Rc<RefCell<usize>>,
 | 
			
		||||
    answer: Rc<String>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl UseBoardHandle {
 | 
			
		||||
    pub fn send_key(&self, k: Key) {
 | 
			
		||||
        let current_attempt_len = self.current_attempt.chars().count();
 | 
			
		||||
 | 
			
		||||
        if self.result.is_some() {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        match k {
 | 
			
		||||
            Key::CharKey(c) => {
 | 
			
		||||
                if current_attempt_len >= 5 {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                let mut new_attempt = (*self.current_attempt).clone();
 | 
			
		||||
                new_attempt.push(c);
 | 
			
		||||
                self.current_attempt.set(new_attempt);
 | 
			
		||||
            }
 | 
			
		||||
            Key::Backspace => {
 | 
			
		||||
                if current_attempt_len == 0 {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                let mut new_attempt = (*self.current_attempt).clone();
 | 
			
		||||
                // This unwrap is safe because the potential failura it's already covered
 | 
			
		||||
                new_attempt.pop().unwrap();
 | 
			
		||||
                self.current_attempt.set(new_attempt);
 | 
			
		||||
            }
 | 
			
		||||
            Key::Enter => {
 | 
			
		||||
                if current_attempt_len < 5 {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                if !WORDS.contains(&*self.current_attempt) {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                let mut new_attempts = (*self.attempts).clone();
 | 
			
		||||
                let new_attempt_row = (*self.current_attempt)
 | 
			
		||||
                    .clone()
 | 
			
		||||
                    .chars()
 | 
			
		||||
                    .zip((*self.answer).chars())
 | 
			
		||||
                    .map(|(att, ans)| {
 | 
			
		||||
                        let status = evaluate_status(ans, att, (*self.answer).clone());
 | 
			
		||||
                        AttemptField {
 | 
			
		||||
                            char_field: att,
 | 
			
		||||
                            status,
 | 
			
		||||
                        }
 | 
			
		||||
                    }).collect();
 | 
			
		||||
                new_attempts.fields.push(new_attempt_row);
 | 
			
		||||
 | 
			
		||||
                self.attempts.set(new_attempts);
 | 
			
		||||
                *self.attempt_index.borrow_mut() += 1;
 | 
			
		||||
 | 
			
		||||
                if (*self.current_attempt) == (*self.answer) {
 | 
			
		||||
                    self.result.set(Some(GameResult::Win));
 | 
			
		||||
                } else if *self.attempt_index.borrow() == MAX_ATTEMPTS {
 | 
			
		||||
                    self.result.set(Some(GameResult::Fail));
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                self.current_attempt.set(String::default());
 | 
			
		||||
            }
 | 
			
		||||
            _ => {}
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[hook]
 | 
			
		||||
pub fn use_board() -> UseBoardHandle {
 | 
			
		||||
    let current_attempt = use_state(|| "".to_string());
 | 
			
		||||
    let attempts: UseStateHandle<Attempts> = use_state(|| Attempts::new());
 | 
			
		||||
    let attempt_index = use_mut_ref(|| 0usize);
 | 
			
		||||
    // let answer = use_memo(|_| get_word_of_the_day(), None::<()>);
 | 
			
		||||
    let answer = use_memo(|_| "ABEJA".to_owned(), None::<()>);
 | 
			
		||||
    let virtual_keyboard = use_state(|| new_empty_virtual_keyboard().into());
 | 
			
		||||
    let result = use_state(|| None::<GameResult>);
 | 
			
		||||
 | 
			
		||||
    let send_key = {
 | 
			
		||||
        let current_attempt = current_attempt.clone();
 | 
			
		||||
        let current_attempt_len = current_attempt.chars().count();
 | 
			
		||||
        let attempts = attempts.clone();
 | 
			
		||||
        let answer = (*answer).clone();
 | 
			
		||||
        let attempt_index = attempt_index.clone();
 | 
			
		||||
        let result = result.clone();
 | 
			
		||||
 | 
			
		||||
        move |k: Key| {}
 | 
			
		||||
    };
 | 
			
		||||
    UseBoardHandle {
 | 
			
		||||
        current_attempt,
 | 
			
		||||
        attempts,
 | 
			
		||||
        attempt_index,
 | 
			
		||||
        virtual_keyboard,
 | 
			
		||||
        result,
 | 
			
		||||
        answer,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										136
									
								
								src/main.rs
								
								
								
								
							
							
						
						
									
										136
									
								
								src/main.rs
								
								
								
								
							| 
						 | 
				
			
			@ -1,62 +1,132 @@
 | 
			
		|||
use yew::prelude::*;
 | 
			
		||||
 | 
			
		||||
use crate::components::{AttemptRow, Board};
 | 
			
		||||
use crate::components::AttemptRow;
 | 
			
		||||
use crate::components::CurrentRow;
 | 
			
		||||
use crate::components::EmptyRow;
 | 
			
		||||
use crate::components::Keyboard;
 | 
			
		||||
use crate::components::ResultBoard;
 | 
			
		||||
use crate::consts::{Key, MAX_ATTEMPTS};
 | 
			
		||||
use crate::hooks::use_board;
 | 
			
		||||
use crate::consts::Key;
 | 
			
		||||
use crate::consts::Result;
 | 
			
		||||
use crate::consts::MAX_ATTEMPTS;
 | 
			
		||||
use crate::services::words::{get_all_words, get_word_of_the_day};
 | 
			
		||||
use chrono::Datelike;
 | 
			
		||||
 | 
			
		||||
use gloo::console;
 | 
			
		||||
 | 
			
		||||
mod components;
 | 
			
		||||
mod consts;
 | 
			
		||||
mod hooks;
 | 
			
		||||
mod services;
 | 
			
		||||
mod utils;
 | 
			
		||||
 | 
			
		||||
#[function_component]
 | 
			
		||||
fn App() -> Html {
 | 
			
		||||
    let board = use_board();
 | 
			
		||||
    let answer = use_state(|| get_word_of_the_day());
 | 
			
		||||
    let all_the_words = use_memo(|_| get_all_words(), 0);
 | 
			
		||||
    let attempts: UseStateHandle<Vec<String>> = use_state(|| vec![String::default(); MAX_ATTEMPTS]);
 | 
			
		||||
    let attempt_index = use_state(|| 0usize);
 | 
			
		||||
    let current_attempt = use_state(|| String::new());
 | 
			
		||||
    let result = use_state(|| None::<Result>);
 | 
			
		||||
 | 
			
		||||
    let onkeypress = {
 | 
			
		||||
        let board = board.clone();
 | 
			
		||||
        console::log!(chrono::Utc::now().year());
 | 
			
		||||
        let current = current_attempt.clone();
 | 
			
		||||
        let answer = answer.clone();
 | 
			
		||||
        let answer_str = answer.clone().to_string();
 | 
			
		||||
        let current_str = current.clone().to_string();
 | 
			
		||||
        let attempts = attempts.clone();
 | 
			
		||||
        let result = result.clone();
 | 
			
		||||
        let index = attempt_index.clone();
 | 
			
		||||
 | 
			
		||||
        Callback::from(move |event: KeyboardEvent| {
 | 
			
		||||
            let key_code = event.key_code();
 | 
			
		||||
            board.send_key(Key::from(key_code));
 | 
			
		||||
        move |event: KeyboardEvent| {
 | 
			
		||||
            console::log!(&event);
 | 
			
		||||
        })
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let onclick = {
 | 
			
		||||
        let board = board.clone();
 | 
			
		||||
            if result.is_some() {
 | 
			
		||||
                return {};
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        Callback::from(move |key| {
 | 
			
		||||
            board.send_key(key);
 | 
			
		||||
        })
 | 
			
		||||
            let key_code = event.key_code();
 | 
			
		||||
 | 
			
		||||
            match Key::from(key_code) {
 | 
			
		||||
                Key::CharKey(c) => {
 | 
			
		||||
                    if current.chars().count() >= 5 {
 | 
			
		||||
                        return ();
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    let mut new_attempt = current_str.clone();
 | 
			
		||||
                    new_attempt.push(c);
 | 
			
		||||
                    console::log!(&new_attempt);
 | 
			
		||||
                    current.set(new_attempt);
 | 
			
		||||
                }
 | 
			
		||||
                Key::Backspace => {
 | 
			
		||||
                    if current.is_empty() {
 | 
			
		||||
                        return ();
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    let mut new_attempt = current_str.clone();
 | 
			
		||||
                    // This unwrap is safe because the potential failura it's already covered
 | 
			
		||||
                    // by the upper if
 | 
			
		||||
                    new_attempt.pop().unwrap();
 | 
			
		||||
                    console::log!(&new_attempt);
 | 
			
		||||
                    current.set(new_attempt);
 | 
			
		||||
                }
 | 
			
		||||
                Key::Enter => {
 | 
			
		||||
                    if current.chars().count() != 5 {
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if !all_the_words.contains(¤t) {
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    let mut new_attempts = attempts.clone().to_vec();
 | 
			
		||||
                    new_attempts[*index] = current_str.clone();
 | 
			
		||||
 | 
			
		||||
                    attempts.set(new_attempts);
 | 
			
		||||
                    current.set(String::default());
 | 
			
		||||
                    index.set(*index + 1);
 | 
			
		||||
 | 
			
		||||
                    if ¤t_str == &answer_str {
 | 
			
		||||
                        result.set(Some(Result::Win));
 | 
			
		||||
                    } else if *index == MAX_ATTEMPTS {
 | 
			
		||||
                        result.set(Some(Result::Fail));
 | 
			
		||||
                    } else {
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                _ => {}
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    html! {
 | 
			
		||||
        <>
 | 
			
		||||
            <h1>{ "Worsdle" }</h1>
 | 
			
		||||
            <Board
 | 
			
		||||
                attempts={ (*board.attempts).clone() }
 | 
			
		||||
                attempt_index={ *board.attempt_index.borrow() }
 | 
			
		||||
                current_attempt={ (*board.current_attempt).clone() }
 | 
			
		||||
                onkeypress={ onkeypress }
 | 
			
		||||
            />
 | 
			
		||||
            <div>
 | 
			
		||||
                <span> {
 | 
			
		||||
                    match (*board.result).clone() {
 | 
			
		||||
                        Some(res) => html! { <ResultBoard attempts={(*board.attempts).clone()} /> },
 | 
			
		||||
                        _ => html! { <Keyboard
 | 
			
		||||
                                        keyboard={ (board.virtual_keyboard).clone() }
 | 
			
		||||
                                        onclick={ onclick } /> }
 | 
			
		||||
                    }
 | 
			
		||||
                } </span>
 | 
			
		||||
            <div class="board" onkeyup={onkeypress} tabindex="0">
 | 
			
		||||
                {
 | 
			
		||||
                    for attempts.clone().iter().enumerate().map(|(i, attempt)| {
 | 
			
		||||
                        let current = current_attempt.clone().to_string();
 | 
			
		||||
                        let attempt = attempt.clone();
 | 
			
		||||
 | 
			
		||||
                        if i < *attempt_index {
 | 
			
		||||
                            let answer = answer.clone().to_string();
 | 
			
		||||
 | 
			
		||||
                            html! { <AttemptRow text={attempt} answer={answer} /> }
 | 
			
		||||
                        } else if i == *attempt_index {
 | 
			
		||||
                            html! { <CurrentRow text={ current } /> }
 | 
			
		||||
                        } else {
 | 
			
		||||
                            html! { <EmptyRow /> }
 | 
			
		||||
                        }
 | 
			
		||||
                    })
 | 
			
		||||
                }
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class={ format!("result {}", if result.is_some() { "" } else { "hidden" }) } >
 | 
			
		||||
            <span> {
 | 
			
		||||
                match *result {
 | 
			
		||||
                    Some(Result::Win) => "Ganaste!!",
 | 
			
		||||
                    Some(Result::Fail) => "Perdiste :c",
 | 
			
		||||
                    _ => "No deberías ver esto"
 | 
			
		||||
                }
 | 
			
		||||
            } </span>
 | 
			
		||||
            < ResultBoard answer={ answer.to_string().clone() } attempts={(*attempts).clone()}  />
 | 
			
		||||
            <p> { "Vuelve mañana para otro desafío :)" } </p>
 | 
			
		||||
        </div>
 | 
			
		||||
        </>
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										45
									
								
								src/utils.rs
								
								
								
								
							
							
						
						
									
										45
									
								
								src/utils.rs
								
								
								
								
							| 
						 | 
				
			
			@ -1,45 +0,0 @@
 | 
			
		|||
use crate::consts::{KeyboardKeyType, Status, VirtualKey};
 | 
			
		||||
 | 
			
		||||
pub fn new_empty_virtual_keyboard() -> [VirtualKey; 29] {
 | 
			
		||||
    [
 | 
			
		||||
        VirtualKey::from_charkey('Q'),
 | 
			
		||||
        VirtualKey::from_charkey('W'),
 | 
			
		||||
        VirtualKey::from_charkey('E'),
 | 
			
		||||
        VirtualKey::from_charkey('R'),
 | 
			
		||||
        VirtualKey::from_charkey('T'),
 | 
			
		||||
        VirtualKey::from_charkey('Y'),
 | 
			
		||||
        VirtualKey::from_charkey('U'),
 | 
			
		||||
        VirtualKey::from_charkey('I'),
 | 
			
		||||
        VirtualKey::from_charkey('O'),
 | 
			
		||||
        VirtualKey::from_charkey('P'),
 | 
			
		||||
        VirtualKey::from_charkey('A'),
 | 
			
		||||
        VirtualKey::from_charkey('S'),
 | 
			
		||||
        VirtualKey::from_charkey('D'),
 | 
			
		||||
        VirtualKey::from_charkey('F'),
 | 
			
		||||
        VirtualKey::from_charkey('G'),
 | 
			
		||||
        VirtualKey::from_charkey('H'),
 | 
			
		||||
        VirtualKey::from_charkey('J'),
 | 
			
		||||
        VirtualKey::from_charkey('K'),
 | 
			
		||||
        VirtualKey::from_charkey('L'),
 | 
			
		||||
        VirtualKey::from_charkey('Ñ'),
 | 
			
		||||
        VirtualKey::from_key(KeyboardKeyType::Backspace),
 | 
			
		||||
        VirtualKey::from_charkey('Z'),
 | 
			
		||||
        VirtualKey::from_charkey('X'),
 | 
			
		||||
        VirtualKey::from_charkey('C'),
 | 
			
		||||
        VirtualKey::from_charkey('V'),
 | 
			
		||||
        VirtualKey::from_charkey('B'),
 | 
			
		||||
        VirtualKey::from_charkey('N'),
 | 
			
		||||
        VirtualKey::from_charkey('M'),
 | 
			
		||||
        VirtualKey::from_key(KeyboardKeyType::Enter),
 | 
			
		||||
    ]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn evaluate_status(ans: char, attr: char, answer: String) -> Status {
 | 
			
		||||
    if ans == attr {
 | 
			
		||||
        Status::Found
 | 
			
		||||
    } else if answer.contains(attr) {
 | 
			
		||||
        Status::Almost
 | 
			
		||||
    } else {
 | 
			
		||||
        Status::NotFound
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,349 +0,0 @@
 | 
			
		|||
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
 | 
			
		||||
 | 
			
		||||
/* Document
 | 
			
		||||
   ========================================================================== */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 1. Correct the line height in all browsers.
 | 
			
		||||
 * 2. Prevent adjustments of font size after orientation changes in iOS.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
html {
 | 
			
		||||
  line-height: 1.15; /* 1 */
 | 
			
		||||
  -webkit-text-size-adjust: 100%; /* 2 */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Sections
 | 
			
		||||
   ========================================================================== */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Remove the margin in all browsers.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
body {
 | 
			
		||||
  margin: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Render the `main` element consistently in IE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
main {
 | 
			
		||||
  display: block;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Correct the font size and margin on `h1` elements within `section` and
 | 
			
		||||
 * `article` contexts in Chrome, Firefox, and Safari.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
h1 {
 | 
			
		||||
  font-size: 2em;
 | 
			
		||||
  margin: 0.67em 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Grouping content
 | 
			
		||||
   ========================================================================== */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 1. Add the correct box sizing in Firefox.
 | 
			
		||||
 * 2. Show the overflow in Edge and IE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
hr {
 | 
			
		||||
  box-sizing: content-box; /* 1 */
 | 
			
		||||
  height: 0; /* 1 */
 | 
			
		||||
  overflow: visible; /* 2 */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 1. Correct the inheritance and scaling of font size in all browsers.
 | 
			
		||||
 * 2. Correct the odd `em` font sizing in all browsers.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
pre {
 | 
			
		||||
  font-family: monospace, monospace; /* 1 */
 | 
			
		||||
  font-size: 1em; /* 2 */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Text-level semantics
 | 
			
		||||
   ========================================================================== */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Remove the gray background on active links in IE 10.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
a {
 | 
			
		||||
  background-color: transparent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 1. Remove the bottom border in Chrome 57-
 | 
			
		||||
 * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
abbr[title] {
 | 
			
		||||
  border-bottom: none; /* 1 */
 | 
			
		||||
  text-decoration: underline; /* 2 */
 | 
			
		||||
  text-decoration: underline dotted; /* 2 */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Add the correct font weight in Chrome, Edge, and Safari.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
b,
 | 
			
		||||
strong {
 | 
			
		||||
  font-weight: bolder;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 1. Correct the inheritance and scaling of font size in all browsers.
 | 
			
		||||
 * 2. Correct the odd `em` font sizing in all browsers.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
code,
 | 
			
		||||
kbd,
 | 
			
		||||
samp {
 | 
			
		||||
  font-family: monospace, monospace; /* 1 */
 | 
			
		||||
  font-size: 1em; /* 2 */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Add the correct font size in all browsers.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
small {
 | 
			
		||||
  font-size: 80%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Prevent `sub` and `sup` elements from affecting the line height in
 | 
			
		||||
 * all browsers.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
sub,
 | 
			
		||||
sup {
 | 
			
		||||
  font-size: 75%;
 | 
			
		||||
  line-height: 0;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  vertical-align: baseline;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub {
 | 
			
		||||
  bottom: -0.25em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sup {
 | 
			
		||||
  top: -0.5em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Embedded content
 | 
			
		||||
   ========================================================================== */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Remove the border on images inside links in IE 10.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
img {
 | 
			
		||||
  border-style: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Forms
 | 
			
		||||
   ========================================================================== */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 1. Change the font styles in all browsers.
 | 
			
		||||
 * 2. Remove the margin in Firefox and Safari.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
button,
 | 
			
		||||
input,
 | 
			
		||||
optgroup,
 | 
			
		||||
select,
 | 
			
		||||
textarea {
 | 
			
		||||
  font-family: inherit; /* 1 */
 | 
			
		||||
  font-size: 100%; /* 1 */
 | 
			
		||||
  line-height: 1.15; /* 1 */
 | 
			
		||||
  margin: 0; /* 2 */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Show the overflow in IE.
 | 
			
		||||
 * 1. Show the overflow in Edge.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
button,
 | 
			
		||||
input { /* 1 */
 | 
			
		||||
  overflow: visible;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Remove the inheritance of text transform in Edge, Firefox, and IE.
 | 
			
		||||
 * 1. Remove the inheritance of text transform in Firefox.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
button,
 | 
			
		||||
select { /* 1 */
 | 
			
		||||
  text-transform: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Correct the inability to style clickable types in iOS and Safari.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
button,
 | 
			
		||||
[type="button"],
 | 
			
		||||
[type="reset"],
 | 
			
		||||
[type="submit"] {
 | 
			
		||||
  -webkit-appearance: button;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Remove the inner border and padding in Firefox.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
button::-moz-focus-inner,
 | 
			
		||||
[type="button"]::-moz-focus-inner,
 | 
			
		||||
[type="reset"]::-moz-focus-inner,
 | 
			
		||||
[type="submit"]::-moz-focus-inner {
 | 
			
		||||
  border-style: none;
 | 
			
		||||
  padding: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Restore the focus styles unset by the previous rule.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
button:-moz-focusring,
 | 
			
		||||
[type="button"]:-moz-focusring,
 | 
			
		||||
[type="reset"]:-moz-focusring,
 | 
			
		||||
[type="submit"]:-moz-focusring {
 | 
			
		||||
  outline: 1px dotted ButtonText;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Correct the padding in Firefox.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
fieldset {
 | 
			
		||||
  padding: 0.35em 0.75em 0.625em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 1. Correct the text wrapping in Edge and IE.
 | 
			
		||||
 * 2. Correct the color inheritance from `fieldset` elements in IE.
 | 
			
		||||
 * 3. Remove the padding so developers are not caught out when they zero out
 | 
			
		||||
 *    `fieldset` elements in all browsers.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
legend {
 | 
			
		||||
  box-sizing: border-box; /* 1 */
 | 
			
		||||
  color: inherit; /* 2 */
 | 
			
		||||
  display: table; /* 1 */
 | 
			
		||||
  max-width: 100%; /* 1 */
 | 
			
		||||
  padding: 0; /* 3 */
 | 
			
		||||
  white-space: normal; /* 1 */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Add the correct vertical alignment in Chrome, Firefox, and Opera.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
progress {
 | 
			
		||||
  vertical-align: baseline;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Remove the default vertical scrollbar in IE 10+.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
textarea {
 | 
			
		||||
  overflow: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 1. Add the correct box sizing in IE 10.
 | 
			
		||||
 * 2. Remove the padding in IE 10.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
[type="checkbox"],
 | 
			
		||||
[type="radio"] {
 | 
			
		||||
  box-sizing: border-box; /* 1 */
 | 
			
		||||
  padding: 0; /* 2 */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Correct the cursor style of increment and decrement buttons in Chrome.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
[type="number"]::-webkit-inner-spin-button,
 | 
			
		||||
[type="number"]::-webkit-outer-spin-button {
 | 
			
		||||
  height: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 1. Correct the odd appearance in Chrome and Safari.
 | 
			
		||||
 * 2. Correct the outline style in Safari.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
[type="search"] {
 | 
			
		||||
  -webkit-appearance: textfield; /* 1 */
 | 
			
		||||
  outline-offset: -2px; /* 2 */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Remove the inner padding in Chrome and Safari on macOS.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
[type="search"]::-webkit-search-decoration {
 | 
			
		||||
  -webkit-appearance: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 1. Correct the inability to style clickable types in iOS and Safari.
 | 
			
		||||
 * 2. Change font properties to `inherit` in Safari.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
::-webkit-file-upload-button {
 | 
			
		||||
  -webkit-appearance: button; /* 1 */
 | 
			
		||||
  font: inherit; /* 2 */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Interactive
 | 
			
		||||
   ========================================================================== */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Add the correct display in Edge, IE 10+, and Firefox.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
details {
 | 
			
		||||
  display: block;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Add the correct display in all browsers.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
summary {
 | 
			
		||||
  display: list-item;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Misc
 | 
			
		||||
   ========================================================================== */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Add the correct display in IE 10+.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
template {
 | 
			
		||||
  display: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Add the correct display in IE 10.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
[hidden] {
 | 
			
		||||
  display: none;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -82,16 +82,3 @@ body {
 | 
			
		|||
    width: 20px;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.keyboard {
 | 
			
		||||
    display: grid;
 | 
			
		||||
    grid-template-columns: repeat(20, 1fr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.keyboard > button {
 | 
			
		||||
    grid-column: span 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.keyboard > button.key-big {
 | 
			
		||||
    grid-column: span 3;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue