diff --git a/assets/main.css b/assets/main.css index d015c5c..051304c 100644 --- a/assets/main.css +++ b/assets/main.css @@ -25,6 +25,44 @@ body { overflow-x: hidden; } +#report { + margin: auto; + width: 100%; + display: flex; + flex-flow: column; + align-items: center; + justify-content: center; + margin-top: 5vh; + + > p { + font-size: 2vw; + + &.correct { + color: var(--correct); + text-shadow: var(--correct-shadow) 0px 0px 30px; + } + + &.wrong { + color: var(--fail); + text-shadow: var(--fail-shadow) 0px 0px 30px; + } + } + + > div { + display: flex; + width: 100%; + height: 100%; + align-items: center; + justify-content: center; + + > button { + width: 50%; + height: 100%; + min-height: 300px; + } + } +} + #counter { margin: 10px; font-size: 20px; @@ -99,11 +137,11 @@ form { text-align: center; display: flex; flex-direction: column; - font-size: 24px; + font-size: 1vw; user-select: none; h1 { - font-size: 3vw; + font-size: 2vw; text-wrap: balance; &.correct { @@ -119,9 +157,9 @@ form { > div { width: 100%; - height: 80px; + height: 10vh; display: flex; - margin-top: 10px; + margin-top: 3vh; align-items: center; align-self: center; box-sizing: border-box; @@ -143,23 +181,32 @@ form { flex-grow: 1; } } +} - > input[type="submit"] { - margin-top: 40px; - height: 70px; - background-color: transparent; - border: none; - color: white; - font-size: 42px; +button, +input[type="submit"] { + margin-top: 40px; + height: 70px; + background-color: transparent; + border: none; + color: white; + font-size: 42px; - &:focus { - outline: none; - } + &:focus { + outline: none; } } @media only screen and (max-width: 540px) { + #report { + > p { + font-size: 6vw; + } + } + form { + font-size: 4vw; + h1 { font-size: 5vw; } @@ -172,12 +219,6 @@ form { @media (hover: hover) { form { - > input[type="submit"]:hover { - font-size: 48px; - color: var(--selection); - cursor: pointer; - } - > div { &:hover:not(.selected) { border: solid 1px var(--hover); @@ -189,4 +230,11 @@ form { } } } + + button:hover, + input[type="submit"]:hover { + font-size: 48px; + color: var(--selection); + cursor: pointer; + } } diff --git a/src/main.rs b/src/main.rs index 40d32a5..ceead6e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,7 @@ use std::{sync::OnceLock, time::Duration}; use async_std::task::sleep; #[cfg(feature = "desktop")] use dioxus::desktop::{Config, LogicalSize, WindowBuilder}; -use dioxus::prelude::*; +use dioxus::{logger::tracing, prelude::*}; #[cfg(feature = "bundled")] use include_dir::{Dir, include_dir}; use models::{Question, Questions}; @@ -118,22 +118,60 @@ fn main() { fn App() -> Element { let questions = get_rand_questions(); + let correct_questions = use_signal(|| 0); + let wrong_questions = use_signal(|| 0); + + let has_finished = use_signal(|| false); + let has_restart = use_signal(|| false); + rsx! { document::Link { rel: "stylesheet", href: MAIN_CSS } - if !questions.is_empty() { - QuestionForm { questions } + p { "{has_restart}" } + if !questions.is_empty() && !has_finished() { + QuestionForm { questions, correct_questions, wrong_questions, has_finished, has_restart } + } + else if has_finished() { + Report { + questions, + correct_questions: correct_questions(), + wrong_questions: wrong_questions(), + has_restart, + } } } } +#[allow(clippy::redundant_closure)] #[component] -pub fn QuestionForm(questions: Vec) -> Element { +pub fn QuestionForm( + questions: Vec, + correct_questions: Signal, + wrong_questions: Signal, + has_finished: Signal, + has_restart: Signal, +) -> Element { let mut questions = use_signal(|| questions); - let mut current = use_signal(move || questions.remove(0)); + let mut current = use_signal(move || questions().remove(0)); + + // use_effect(move || { + // let mut has_restart_lock = has_restart.write(); + // tracing::info!("called new questions effect {}", *has_restart_lock); + // if *has_restart_lock { + // tracing::info!("actually passing effect"); + // let mut questions_lock = questions.write(); + // + // *questions_lock = get_rand_questions(); + // current.set(questions_lock.remove(0)); + // + // correct_questions.set(0); + // wrong_questions.set(0); + // *has_restart_lock = false; + // has_finished.set(false); + // } + // }); let total_correct = use_memo(move || { - current - .read() + current() .answers .iter() .filter(|a| a.is_correct.unwrap_or_default()) @@ -155,12 +193,6 @@ pub fn QuestionForm(questions: Vec) -> Element { correctly_checked.saturating_sub(incorrectly_checked) }); - let total_questions = get_questions().len(); - let current_question = use_memo(move || questions().len()); - let left_questions = use_memo(move || total_questions - current_question()); - let mut correct_questions = use_signal(|| 0); - let mut wrong_questions = use_signal(|| 0); - let mut correct_animation = use_signal(|| false); let mut wrong_animation = use_signal(|| false); @@ -173,15 +205,21 @@ pub fn QuestionForm(questions: Vec) -> Element { if is_correct || is_wrong { sleep(Duration::from_millis(600)).await; - // Uncheck all the answers - current().answers.iter_mut().for_each(|a| a.checked = false); - + let mut current_lock = current.write(); let mut correct_questions_lock = correct_questions.write(); let mut wrong_questions_lock = wrong_questions.write(); + let mut questions_lock = questions.write(); + let mut has_finished_lock = has_finished.write(); + + // Uncheck all the answers + current_lock + .answers + .iter_mut() + .for_each(|a| a.checked = false); // Get a new question or reroll the list - if !questions().is_empty() { - current.set(questions.remove(0)); + if !questions_lock.is_empty() { + *current_lock = questions_lock.remove(0); // Update the correct/wrong counters if is_correct { @@ -189,12 +227,10 @@ pub fn QuestionForm(questions: Vec) -> Element { } else if is_wrong { *wrong_questions_lock += 1; } - } else { - questions.set(get_rand_questions()); - current.set(questions.remove(0)); - *correct_questions_lock = 0; - *wrong_questions_lock = 0; + if questions_lock.is_empty() { + *has_finished_lock = true; + } } // Reset animation flags @@ -215,20 +251,8 @@ pub fn QuestionForm(questions: Vec) -> Element { }); rsx! { - ResultPopup { is_correct: correct_animation, is_wrong: wrong_animation }, - div { - id: "counter", - div { "{left_questions}" } - div { - class: "correct", - "{correct_questions}" - } - div { - class: "wrong", - "{wrong_questions}" - } - div { "{total_questions}" } - }, + Result { is_correct: correct_animation(), is_wrong: wrong_animation() }, + Info { questions, correct_questions, wrong_questions }, form { id: "form", onsubmit: move |_| { @@ -303,20 +327,84 @@ pub fn AnswerCheckbox(current: Signal, id: usize) -> Element { #[allow(clippy::redundant_closure)] #[component] -pub fn ResultPopup(is_correct: Signal, is_wrong: Signal) -> Element { - let is_correct = use_memo(move || is_correct()); - let is_wrong = use_memo(move || is_wrong()); - let is_visible = use_memo(move || is_correct() || is_wrong()); +pub fn Result(is_correct: bool, is_wrong: bool) -> Element { + let is_visible = is_correct || is_wrong; rsx! { div { id: "result", - class: if is_visible() { "visible" }, + class: if is_visible { "visible" }, div { - class: if is_correct() { "correct" }, - class: if is_wrong() { "wrong" }, - if is_correct() { "✓" } else { "X" } + class: if is_correct { "correct" }, + class: if is_wrong { "wrong" }, + if is_correct { "✓" } else { "X" } + } + } + } +} + +#[allow(clippy::redundant_closure)] +#[component] +pub fn Info( + questions: Signal>, + correct_questions: Signal, + wrong_questions: Signal, +) -> Element { + let total_questions = get_questions().len(); + let current_question = use_memo(move || questions().len()); + let left_questions = use_memo(move || total_questions - current_question()); + + rsx! { + div { + id: "counter", + + div { "{left_questions}" } + div { + class: "correct", + "{correct_questions}" + } + div { + class: "wrong", + "{wrong_questions}" + } + div { "{total_questions}" } + } + } +} + +#[component] +pub fn Report( + questions: Vec, + correct_questions: i32, + wrong_questions: i32, + has_restart: Signal, +) -> Element { + let questions_size = questions.len(); + + rsx! { + div { + id: "report", + + p { "Questions: {questions_size}" }, + p { + class: "correct", + "Correct: {correct_questions}" + }, + p { + class: "wrong", + "Wrong: {wrong_questions}" + }, + div { + button { + // onclick: move |_| { + // *has_restart.write() = true; + // }, + "Restart" + }, + button { + "Restart with only wrong questions" + } } } }