Compare commits
	
		
			4 Commits 
		
	
	
		
			d521d69eac
			...
			8d02ea1b6a
		
	
	| Author | SHA1 | Date | 
|---|---|---|
| 
							
							
								
								 | 
						8d02ea1b6a | |
| 
							
							
								
								 | 
						f8108ed7b7 | |
| 
							
							
								
								 | 
						d64996d5dd | |
| 
							
							
								
								 | 
						8420721145 | 
| 
						 | 
					@ -0,0 +1,19 @@
 | 
				
			||||||
 | 
					Copyright (c) 2023 Kirbylife <hola@kirbylife.dev>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
				
			||||||
 | 
					of this software and associated documentation files (the "Software"), to deal
 | 
				
			||||||
 | 
					in the Software without restriction, including without limitation the rights
 | 
				
			||||||
 | 
					to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
				
			||||||
 | 
					copies of the Software, and to permit persons to whom the Software is
 | 
				
			||||||
 | 
					furnished to do so, subject to the following conditions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The above copyright notice and this permission notice shall be included in all
 | 
				
			||||||
 | 
					copies or substantial portions of the Software.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
				
			||||||
 | 
					IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
				
			||||||
 | 
					FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
				
			||||||
 | 
					AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
				
			||||||
 | 
					LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
				
			||||||
 | 
					OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
				
			||||||
 | 
					SOFTWARE.
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,23 @@
 | 
				
			||||||
 | 
					## Worsdle
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A simple [Wordle](https://es.wikipedia.org/wiki/Wordle) clone written in Rust and Yem with spanish words.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Dependencies to build
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- [Trunk](https://trunkrs.dev/)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### How to build to production
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. `cargo install --locked trunk`
 | 
				
			||||||
 | 
					2. `git clone https://git.kirbylife.dev/kirbylife/worsdle`
 | 
				
			||||||
 | 
					3. `cd worsdle`
 | 
				
			||||||
 | 
					4. `trunk build --release`
 | 
				
			||||||
 | 
					5. The build should be in the `dist/` folder.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Run a dev server
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. `trunk serve`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Contribute
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you want to add a new word to the list, you can pass it to me through any social network.
 | 
				
			||||||
| 
						 | 
					@ -2,12 +2,13 @@
 | 
				
			||||||
<html lang="es">
 | 
					<html lang="es">
 | 
				
			||||||
<head>
 | 
					<head>
 | 
				
			||||||
    <meta charset="UTF-8">
 | 
					    <meta charset="UTF-8">
 | 
				
			||||||
 | 
					    <meta content="width=device-width, initial-scale=1.0" name="viewport"/>
 | 
				
			||||||
    <title>Yew App</title>
 | 
					    <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 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" />
 | 
					          rel="stylesheet">
 | 
				
			||||||
    <link data-trunk rel="css" href="static/css/normalize.css" />
 | 
					    <link data-trunk href="static/css/styles.css" rel="css"/>
 | 
				
			||||||
 | 
					    <link data-trunk href="static/css/normalize.css" rel="css"/>
 | 
				
			||||||
</head>
 | 
					</head>
 | 
				
			||||||
<body>
 | 
					<body>
 | 
				
			||||||
<h1>Hola mundo</h1>
 | 
					 | 
				
			||||||
</body>
 | 
					</body>
 | 
				
			||||||
</html>
 | 
					</html>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
use crate::consts::{Key, KeyboardKeyType, VirtualKey};
 | 
					use crate::consts::{Key, KeyboardKeyType, VirtualKey, Status};
 | 
				
			||||||
use yew::prelude::*;
 | 
					use yew::prelude::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Properties, PartialEq)]
 | 
					#[derive(Properties, PartialEq)]
 | 
				
			||||||
| 
						 | 
					@ -21,7 +21,19 @@ pub fn Keyboard(props: &KeyboardProps) -> Html {
 | 
				
			||||||
        <div class="keyboard"> {
 | 
					        <div class="keyboard"> {
 | 
				
			||||||
            for (props.keyboard).iter().map(|vk: &VirtualKey| {
 | 
					            for (props.keyboard).iter().map(|vk: &VirtualKey| {
 | 
				
			||||||
                match vk.key {
 | 
					                match vk.key {
 | 
				
			||||||
                    KeyboardKeyType::CharKey(c) => html! { <button onclick={ handle_click(Key::CharKey(c)) }> { c } </button> },
 | 
					                    KeyboardKeyType::CharKey(c) => html! {
 | 
				
			||||||
 | 
					                        <button
 | 
				
			||||||
 | 
					                            class={
 | 
				
			||||||
 | 
					                                match vk.status {
 | 
				
			||||||
 | 
					                                    Some(Status::Found) => "correct",
 | 
				
			||||||
 | 
					                                    Some(Status::NotFound) => "missed",
 | 
				
			||||||
 | 
					                                    Some(Status::Almost) => "almost",
 | 
				
			||||||
 | 
					                                    None => ""
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            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::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> }
 | 
					                    KeyboardKeyType::Enter => html! { <button onclick={ handle_click(Key::Enter) }  class="key-big"> { "Enviar" } </button> }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
use crate::consts::GameResult;
 | 
					use crate::consts::{GameResult, MAX_ATTEMPTS};
 | 
				
			||||||
use yew::prelude::*;
 | 
					use yew::prelude::*;
 | 
				
			||||||
use crate::consts::{Attempts, Status};
 | 
					use crate::consts::{Attempts, Status};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,20 +14,26 @@ pub fn ResultBoard(props: &ResultBoardProps) -> Html {
 | 
				
			||||||
    } = props;
 | 
					    } = props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    html! {
 | 
					    html! {
 | 
				
			||||||
        <div class="result-board"> {
 | 
					        <div class="result-board">
 | 
				
			||||||
 | 
					            <p>
 | 
				
			||||||
 | 
					                { format!("Palabra encontrada en {}/{} intentos", attempts.fields.len(), MAX_ATTEMPTS) }
 | 
				
			||||||
 | 
					            </p><br/>
 | 
				
			||||||
 | 
					            <p> {
 | 
				
			||||||
            for attempts.fields.iter().map(|attempt| {
 | 
					            for attempts.fields.iter().map(|attempt| {
 | 
				
			||||||
                html_nested! {
 | 
					                html_nested! {
 | 
				
			||||||
                    <p class={ "result-board" }> {
 | 
					                    <> {
 | 
				
			||||||
                        for attempt.iter().map(| att| {
 | 
					                        for attempt.iter().map(| att| {
 | 
				
			||||||
                            match att.status {
 | 
					                            match att.status {
 | 
				
			||||||
                                Status::Found => html_nested! { <> { "🟩" } </> },
 | 
					                                Status::Found => html_nested! { <> { "🟩" } </> },
 | 
				
			||||||
                                Status::Almost => html_nested! { <span>{ "🟨" }</span> },
 | 
					                                Status::Almost => html_nested! { <>{ "🟨" }</> },
 | 
				
			||||||
                                Status::NotFound => html_nested! { <span>{ "⬜" }</span> }
 | 
					                                Status::NotFound => html_nested! { <>{ "⬛" }</> }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        })
 | 
				
			||||||
 | 
					                    } <br/></>
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
            } </p>
 | 
					            } </p>
 | 
				
			||||||
                }
 | 
					        </div>
 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
        } </div>
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,6 +10,15 @@ pub enum KeyboardKeyType {
 | 
				
			||||||
    CharKey(char),
 | 
					    CharKey(char),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl KeyboardKeyType {
 | 
				
			||||||
 | 
					    pub fn cmp_char(&self, char_to_compare: &char) -> bool {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            KeyboardKeyType::CharKey(ch) => ch == char_to_compare,
 | 
				
			||||||
 | 
					            _ => false
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone, PartialEq)]
 | 
					#[derive(Clone, PartialEq)]
 | 
				
			||||||
pub enum Status {
 | 
					pub enum Status {
 | 
				
			||||||
    NotFound,
 | 
					    NotFound,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
use crate::consts::{AttemptField, Attempts, GameResult, Key, VirtualKey, MAX_ATTEMPTS};
 | 
					use crate::consts::{AttemptField, Attempts, GameResult, Key, VirtualKey, MAX_ATTEMPTS, Status};
 | 
				
			||||||
use crate::services::words::{get_word_of_the_day, WORDS};
 | 
					use crate::services::words::{get_word_of_the_day, WORDS};
 | 
				
			||||||
use crate::utils::{evaluate_status, new_empty_virtual_keyboard};
 | 
					use crate::utils::{evaluate_status, new_empty_virtual_keyboard};
 | 
				
			||||||
use std::cell::RefCell;
 | 
					use std::cell::RefCell;
 | 
				
			||||||
| 
						 | 
					@ -64,8 +64,22 @@ impl UseBoardHandle {
 | 
				
			||||||
                            char_field: att,
 | 
					                            char_field: att,
 | 
				
			||||||
                            status,
 | 
					                            status,
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }).collect();
 | 
					                    }).collect::<Vec<AttemptField>>();
 | 
				
			||||||
                new_attempts.fields.push(new_attempt_row);
 | 
					                new_attempts.fields.push(new_attempt_row.clone());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let mut new_keyboard = (*self.virtual_keyboard).clone();
 | 
				
			||||||
 | 
					                for key in new_keyboard.iter_mut() {
 | 
				
			||||||
 | 
					                    for attempt_field in new_attempt_row.iter() {
 | 
				
			||||||
 | 
					                        if key.key.cmp_char(&attempt_field.char_field) {
 | 
				
			||||||
 | 
					                            if key.status.is_none() {
 | 
				
			||||||
 | 
					                                key.status = Some(attempt_field.status.clone());
 | 
				
			||||||
 | 
					                            } else if key.status == Some(Status::Almost) && attempt_field.status == Status::Found {
 | 
				
			||||||
 | 
					                                key.status = Some(Status::Found);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                self.virtual_keyboard.set(new_keyboard);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                self.attempts.set(new_attempts);
 | 
					                self.attempts.set(new_attempts);
 | 
				
			||||||
                *self.attempt_index.borrow_mut() += 1;
 | 
					                *self.attempt_index.borrow_mut() += 1;
 | 
				
			||||||
| 
						 | 
					@ -88,8 +102,7 @@ pub fn use_board() -> UseBoardHandle {
 | 
				
			||||||
    let current_attempt = use_state(|| "".to_string());
 | 
					    let current_attempt = use_state(|| "".to_string());
 | 
				
			||||||
    let attempts: UseStateHandle<Attempts> = use_state(|| Attempts::new());
 | 
					    let attempts: UseStateHandle<Attempts> = use_state(|| Attempts::new());
 | 
				
			||||||
    let attempt_index = use_mut_ref(|| 0usize);
 | 
					    let attempt_index = use_mut_ref(|| 0usize);
 | 
				
			||||||
    // let answer = use_memo(|_| get_word_of_the_day(), None::<()>);
 | 
					    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 virtual_keyboard = use_state(|| new_empty_virtual_keyboard().into());
 | 
				
			||||||
    let result = use_state(|| None::<GameResult>);
 | 
					    let result = use_state(|| None::<GameResult>);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										13
									
								
								src/main.rs
								
								
								
								
							
							
						
						
									
										13
									
								
								src/main.rs
								
								
								
								
							| 
						 | 
					@ -40,7 +40,10 @@ fn App() -> Html {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    html! {
 | 
					    html! {
 | 
				
			||||||
        <>
 | 
					        <>
 | 
				
			||||||
 | 
					            <header>
 | 
				
			||||||
                <h1>{ "Worsdle" }</h1>
 | 
					                <h1>{ "Worsdle" }</h1>
 | 
				
			||||||
 | 
					            </header>
 | 
				
			||||||
 | 
					            <main>
 | 
				
			||||||
            <Board
 | 
					            <Board
 | 
				
			||||||
                attempts={ (*board.attempts).clone() }
 | 
					                attempts={ (*board.attempts).clone() }
 | 
				
			||||||
                attempt_index={ *board.attempt_index.borrow() }
 | 
					                attempt_index={ *board.attempt_index.borrow() }
 | 
				
			||||||
| 
						 | 
					@ -57,6 +60,16 @@ fn App() -> Html {
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                } </span>
 | 
					                } </span>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
 | 
					            </main>
 | 
				
			||||||
 | 
					            <footer>
 | 
				
			||||||
 | 
					                <small> {
 | 
				
			||||||
 | 
					                    html_nested! {
 | 
				
			||||||
 | 
					                        <>
 | 
				
			||||||
 | 
					                        { "Hecho por " } <a href={ "https://kirbylife.dev" }> { "kirbylife" } </a>
 | 
				
			||||||
 | 
					                        </>
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                } </small>
 | 
				
			||||||
 | 
					            </footer>
 | 
				
			||||||
        </>
 | 
					        </>
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,34 +4,40 @@ body > * {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
body {
 | 
					body {
 | 
				
			||||||
    min-height: 99dvh;
 | 
					    min-height: 99dvh;
 | 
				
			||||||
    margin-left: 150px;
 | 
					    display: grid;
 | 
				
			||||||
    margin-right: 150px;
 | 
					    grid-template-rows: auto 1fr auto;
 | 
				
			||||||
    display: flex;
 | 
					    justify-items: center;
 | 
				
			||||||
    align-items: center;
 | 
					    gap: 5px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					main {
 | 
				
			||||||
 | 
					    padding-left: 20px;
 | 
				
			||||||
 | 
					    padding-right: 20px;
 | 
				
			||||||
 | 
					    display: flex !important;
 | 
				
			||||||
    flex-direction: column;
 | 
					    flex-direction: column;
 | 
				
			||||||
 | 
					    align-items: center;
 | 
				
			||||||
 | 
					    gap: 10px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.board {
 | 
					.board {
 | 
				
			||||||
    width: 25%;
 | 
					 | 
				
			||||||
    height: 25%;
 | 
					 | 
				
			||||||
    display: grid;
 | 
					    display: grid;
 | 
				
			||||||
 | 
					    width: min-content;
 | 
				
			||||||
    grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
 | 
					    grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
 | 
				
			||||||
    justify-items: center;
 | 
					    justify-items: center;
 | 
				
			||||||
    justify-self: auto;
 | 
					    gap: 5px;
 | 
				
			||||||
    gap: 10px;
 | 
					 | 
				
			||||||
    padding-bottom: 10px;
 | 
					    padding-bottom: 10px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.board > p {
 | 
					.board > p {
 | 
				
			||||||
    display: flex;
 | 
					    display: flex;
 | 
				
			||||||
    width: 70px;
 | 
					    width: 50px;
 | 
				
			||||||
    height: 70px;
 | 
					    aspect-ratio: 1/1;
 | 
				
			||||||
    border: 3px solid #444444;
 | 
					    border: 3px solid #444444;
 | 
				
			||||||
    border-radius: 10px;
 | 
					    border-radius: 10px;
 | 
				
			||||||
    justify-content: center;
 | 
					    justify-content: center;
 | 
				
			||||||
    align-items: center;
 | 
					    align-items: center;
 | 
				
			||||||
    margin: 0;
 | 
					    margin: 0;
 | 
				
			||||||
    font-size: 40px;
 | 
					    font-size: 30px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.correct {
 | 
					.correct {
 | 
				
			||||||
| 
						 | 
					@ -69,18 +75,15 @@ body {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.result-board {
 | 
					.result-board {
 | 
				
			||||||
    display: grid;
 | 
					    display: flex;
 | 
				
			||||||
    grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
 | 
					    flex-direction: column;
 | 
				
			||||||
    width: fit-content;
 | 
					    align-items: center;
 | 
				
			||||||
    gap: 2px;
 | 
					    gap: 5px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.result-board > span {
 | 
					.result-board > p {
 | 
				
			||||||
    margin: 0;
 | 
					    margin: 0;
 | 
				
			||||||
    font-size: 20px;
 | 
					    font-size: 20px;
 | 
				
			||||||
    height: 20px;
 | 
					 | 
				
			||||||
    width: 20px;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.keyboard {
 | 
					.keyboard {
 | 
				
			||||||
| 
						 | 
					@ -90,6 +93,8 @@ body {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.keyboard > button {
 | 
					.keyboard > button {
 | 
				
			||||||
    grid-column: span 2;
 | 
					    grid-column: span 2;
 | 
				
			||||||
 | 
					    width: auto;
 | 
				
			||||||
 | 
					    height: 60px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.keyboard > button.key-big {
 | 
					.keyboard > button.key-big {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue