Skip to content

Commit

Permalink
text entry
Browse files Browse the repository at this point in the history
  • Loading branch information
AdamSteinberg1 committed Nov 11, 2023
1 parent 8ea2d30 commit 961e2e4
Show file tree
Hide file tree
Showing 8 changed files with 187 additions and 31 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ getrandom = { version = "0.2.10", features = ["js"] }
gloo = "0.10.0"
itertools = "0.11.0"
rand = "0.8.5"
web-sys = "0.3.64"
web-sys = { version = "0.3.64", features = ["DomTokenList"] }
structmap = "0.1.6"
structmap-derive = "0.1.6"
wasm-bindgen = "0.2.87"
Expand Down
23 changes: 23 additions & 0 deletions src/components/button_input.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use ::yew::prelude::*;

#[derive(PartialEq, Properties)]
pub struct Props {
pub is_revealed: bool,
pub on_reveal: Callback<MouseEvent>,
pub on_new_pokemon: Callback<MouseEvent>,
}

#[function_component]
pub fn ButtonInput(
Props {
is_revealed,
on_reveal,
on_new_pokemon,
}: &Props,
) -> Html {
if *is_revealed {
html! {<button type="button" onclick={on_new_pokemon.clone()}>{"Next"}</button>}
} else {
html! {<button type="button" onclick={on_reveal.clone()}>{"Reveal"}</button>}
}
}
69 changes: 41 additions & 28 deletions src/components/guesser.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
use crate::{
components::{pokemon_image::PokemonImage, pokemon_label::PokemonLabel},
components::{
button_input::ButtonInput, pokemon_image::PokemonImage, pokemon_label::PokemonLabel,
text_input::TextInput,
},
models::settings::Settings,
util::fetch_pokemons,
};
use ::yew::prelude::*;
use gloo::console::log;
use futures::TryFutureExt;
use gloo::console::error;
use std::rc::Rc;
use yew::suspense::use_future;

#[derive(PartialEq, Properties)]
Expand All @@ -15,7 +20,15 @@ pub struct Props {
#[function_component]
pub fn Guesser(Props { settings }: &Props) -> HtmlResult {
let is_name_revealed = use_state_eq(|| false);
let pokemons = use_future(fetch_pokemons)?;
let pokemons = use_future(|| fetch_pokemons().map_ok(Rc::new))?;

let pokemons = match *pokemons {
Ok(ref pokemons) => Rc::clone(pokemons),
Err(ref e) => {
error!(format!("Error when fetching pokemon data:\n{:?}", e));
return Ok(html! {<p><span>{"An error has occurred. 😢"}</span></p>});
}
};

let on_reveal = {
let is_name_revealed = is_name_revealed.clone();
Expand All @@ -26,35 +39,35 @@ pub fn Guesser(Props { settings }: &Props) -> HtmlResult {

let on_new_pokemon = {
let is_name_revealed = is_name_revealed.clone();
let pokemons = Rc::clone(&pokemons);
Callback::from(move |_| {
is_name_revealed.set(false);
pokemons.next();
})
};

match *pokemons {
Err(ref e) => {
log!(format!("Error when fetching pokemon data:\n{:?}", e));
Ok(html! {<p><span>{"An error has occurred. 😢"}</span></p>})
}
Ok(ref pokemons) => {
let pokemon = if *is_name_revealed {
pokemons.current()
} else {
pokemons.next()
};
let next_pokemon = pokemons.peek();
Ok(html! {
<>
<link rel="prefetch" href={next_pokemon.image.clone()} as="image" />
<PokemonImage silhouette={settings.silhouette && !(*is_name_revealed)} image={pokemon.image.clone()}/>
let pokemon = pokemons.current();
let next_pokemon = pokemons.peek();
Ok(html! {
<>
<link rel="prefetch" href={next_pokemon.image.clone()} as="image" />
<PokemonImage silhouette={settings.silhouette && !(*is_name_revealed)} image={pokemon.image.clone()}/>
if settings.text_entry {
if *is_name_revealed {
<PokemonLabel is_revealed={*is_name_revealed} name={pokemon.name.clone()} id={pokemon.id}/>
if *is_name_revealed {
<button type="button" onclick={on_new_pokemon.clone()}>{"Next"}</button>
} else {
<button type="button" onclick={on_reveal.clone()}>{"Reveal"}</button>
}
</>
})
}
}
}
<TextInput
is_revealed={*is_name_revealed}
{on_reveal}
{on_new_pokemon}
name={pokemon.name.clone()}/>
} else {
<PokemonLabel is_revealed={*is_name_revealed} name={pokemon.name.clone()} id={pokemon.id}/>
<ButtonInput
is_revealed={*is_name_revealed}
{on_reveal}
{on_new_pokemon}/>
}
</>
})
}
2 changes: 2 additions & 0 deletions src/components/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
pub mod button_input;
pub mod guesser;
pub mod pokemon_image;
pub mod pokemon_label;
pub mod repo_link;
pub mod settings_menu;
pub mod starburst;
pub mod text_input;
pub mod title;
2 changes: 1 addition & 1 deletion src/components/pokemon_image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use ::yew::prelude::*;
#[derive(PartialEq, Properties)]
pub struct Props {
pub silhouette: bool,
pub image: String,
pub image: AttrValue,
}

#[function_component]
Expand Down
2 changes: 1 addition & 1 deletion src/components/pokemon_label.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use ::yew::prelude::*;
#[derive(PartialEq, Properties)]
pub struct Props {
pub is_revealed: bool,
pub name: String,
pub name: AttrValue,
pub id: u16,
}

Expand Down
71 changes: 71 additions & 0 deletions src/components/text_input.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
use ::yew::prelude::*;
use wasm_bindgen::JsCast;
use web_sys::HtmlElement;
use web_sys::HtmlInputElement;

#[derive(PartialEq, Properties)]
pub struct Props {
pub is_revealed: bool,
pub on_reveal: Callback<MouseEvent>,
pub on_new_pokemon: Callback<MouseEvent>,
pub name: AttrValue,
}

#[function_component]
pub fn TextInput(
Props {
name,
is_revealed,
on_reveal,
on_new_pokemon,
}: &Props,
) -> Html {
let on_submit = {
let name = name.clone();
let on_reveal = on_reveal.clone();
Callback::from(move |event: MouseEvent| {
let target: HtmlInputElement = event.target_unchecked_into();
let text_input: HtmlInputElement =
target.previous_element_sibling().unwrap().unchecked_into();
let guess = text_input.value();
if guess.trim().eq_ignore_ascii_case(&name) {
on_reveal.emit(event);
} else {
text_input
.parent_element()
.map(|parent| parent.class_list().add_1("incorrect-guess"));
}
})
};

let onkeydown = Callback::from(|event: KeyboardEvent| {
if event.key() == "Enter" {
let target: HtmlInputElement = event.target_unchecked_into();
let target = if target.id() == "submit" {
target
} else {
target.next_element_sibling().unwrap().unchecked_into()
};
target.click();
}
});

let onanimationend = Callback::from(move |event: AnimationEvent| {
let target: HtmlElement = event.target_unchecked_into();
let _ = target.class_list().remove_1("incorrect-guess");
});

html! {
<>
if *is_revealed {
<button type="button" onclick={on_new_pokemon}>{"Next"}</button>
} else {
<div class="text-guess" {onanimationend}>
<input type="text" id="guess" onkeydown={onkeydown.clone()}/>
<input type="button" id="submit" value="🡆" onclick={on_submit} {onkeydown}/>
</div>
<button type="button" onclick={on_reveal.clone()}>{"Reveal"}</button>
}
</>
}
}
47 changes: 47 additions & 0 deletions styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -158,4 +158,51 @@ p>span {
border-color: var(--blue);
border-width: 0.1rem;
border-style: solid;
}

@keyframes shake {
0% {
transform: translate(0rem);
}

25% {
transform: translate(0.5rem);
}

75% {
transform: translate(-0.5rem);
}

100% {
transform: translate(0rem);
}
}

.incorrect-guess {
animation: shake 0.2s ease-in-out 0s 2;
}

.text-guess {
display: inline-block;
margin-bottom: 1.37rem;
}

.text-guess>* {
font-size: 1.7em;
border-color: var(--blue);
border-radius: 0.3rem;
border-color: var(--blue);
border-width: 0.1rem;
border-style: solid;
}

.text-guess>input[type=text] {
max-width: 50vw;
font-size: 2em;
text-align: center;
}

.text-guess>input[type=button] {
color: var(--blue);
background-color: var(--yellow);
}

0 comments on commit 961e2e4

Please sign in to comment.