Initial reports page at the end
parent
c2435f4c24
commit
46acb8c196
|
@ -25,6 +25,44 @@ body {
|
||||||
overflow-x: hidden;
|
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 {
|
#counter {
|
||||||
margin: 10px;
|
margin: 10px;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
|
@ -99,11 +137,11 @@ form {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
font-size: 24px;
|
font-size: 1vw;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
font-size: 3vw;
|
font-size: 2vw;
|
||||||
text-wrap: balance;
|
text-wrap: balance;
|
||||||
|
|
||||||
&.correct {
|
&.correct {
|
||||||
|
@ -119,9 +157,9 @@ form {
|
||||||
|
|
||||||
> div {
|
> div {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 80px;
|
height: 10vh;
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-top: 10px;
|
margin-top: 3vh;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
align-self: center;
|
align-self: center;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
@ -143,8 +181,10 @@ form {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
> input[type="submit"] {
|
button,
|
||||||
|
input[type="submit"] {
|
||||||
margin-top: 40px;
|
margin-top: 40px;
|
||||||
height: 70px;
|
height: 70px;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
|
@ -155,11 +195,18 @@ form {
|
||||||
&:focus {
|
&:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 540px) {
|
@media only screen and (max-width: 540px) {
|
||||||
|
#report {
|
||||||
|
> p {
|
||||||
|
font-size: 6vw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
form {
|
form {
|
||||||
|
font-size: 4vw;
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
font-size: 5vw;
|
font-size: 5vw;
|
||||||
}
|
}
|
||||||
|
@ -172,12 +219,6 @@ form {
|
||||||
|
|
||||||
@media (hover: hover) {
|
@media (hover: hover) {
|
||||||
form {
|
form {
|
||||||
> input[type="submit"]:hover {
|
|
||||||
font-size: 48px;
|
|
||||||
color: var(--selection);
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
> div {
|
> div {
|
||||||
&:hover:not(.selected) {
|
&:hover:not(.selected) {
|
||||||
border: solid 1px var(--hover);
|
border: solid 1px var(--hover);
|
||||||
|
@ -189,4 +230,11 @@ form {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button:hover,
|
||||||
|
input[type="submit"]:hover {
|
||||||
|
font-size: 48px;
|
||||||
|
color: var(--selection);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
178
src/main.rs
178
src/main.rs
|
@ -4,7 +4,7 @@ use std::{sync::OnceLock, time::Duration};
|
||||||
use async_std::task::sleep;
|
use async_std::task::sleep;
|
||||||
#[cfg(feature = "desktop")]
|
#[cfg(feature = "desktop")]
|
||||||
use dioxus::desktop::{Config, LogicalSize, WindowBuilder};
|
use dioxus::desktop::{Config, LogicalSize, WindowBuilder};
|
||||||
use dioxus::prelude::*;
|
use dioxus::{logger::tracing, prelude::*};
|
||||||
#[cfg(feature = "bundled")]
|
#[cfg(feature = "bundled")]
|
||||||
use include_dir::{Dir, include_dir};
|
use include_dir::{Dir, include_dir};
|
||||||
use models::{Question, Questions};
|
use models::{Question, Questions};
|
||||||
|
@ -118,22 +118,60 @@ fn main() {
|
||||||
fn App() -> Element {
|
fn App() -> Element {
|
||||||
let questions = get_rand_questions();
|
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! {
|
rsx! {
|
||||||
document::Link { rel: "stylesheet", href: MAIN_CSS }
|
document::Link { rel: "stylesheet", href: MAIN_CSS }
|
||||||
if !questions.is_empty() {
|
p { "{has_restart}" }
|
||||||
QuestionForm { questions }
|
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]
|
#[component]
|
||||||
pub fn QuestionForm(questions: Vec<Question>) -> Element {
|
pub fn QuestionForm(
|
||||||
|
questions: Vec<Question>,
|
||||||
|
correct_questions: Signal<i32>,
|
||||||
|
wrong_questions: Signal<i32>,
|
||||||
|
has_finished: Signal<bool>,
|
||||||
|
has_restart: Signal<bool>,
|
||||||
|
) -> Element {
|
||||||
let mut questions = use_signal(|| questions);
|
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 || {
|
let total_correct = use_memo(move || {
|
||||||
current
|
current()
|
||||||
.read()
|
|
||||||
.answers
|
.answers
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|a| a.is_correct.unwrap_or_default())
|
.filter(|a| a.is_correct.unwrap_or_default())
|
||||||
|
@ -155,12 +193,6 @@ pub fn QuestionForm(questions: Vec<Question>) -> Element {
|
||||||
correctly_checked.saturating_sub(incorrectly_checked)
|
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 correct_animation = use_signal(|| false);
|
||||||
let mut wrong_animation = use_signal(|| false);
|
let mut wrong_animation = use_signal(|| false);
|
||||||
|
|
||||||
|
@ -173,15 +205,21 @@ pub fn QuestionForm(questions: Vec<Question>) -> Element {
|
||||||
if is_correct || is_wrong {
|
if is_correct || is_wrong {
|
||||||
sleep(Duration::from_millis(600)).await;
|
sleep(Duration::from_millis(600)).await;
|
||||||
|
|
||||||
// Uncheck all the answers
|
let mut current_lock = current.write();
|
||||||
current().answers.iter_mut().for_each(|a| a.checked = false);
|
|
||||||
|
|
||||||
let mut correct_questions_lock = correct_questions.write();
|
let mut correct_questions_lock = correct_questions.write();
|
||||||
let mut wrong_questions_lock = wrong_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
|
// Get a new question or reroll the list
|
||||||
if !questions().is_empty() {
|
if !questions_lock.is_empty() {
|
||||||
current.set(questions.remove(0));
|
*current_lock = questions_lock.remove(0);
|
||||||
|
|
||||||
// Update the correct/wrong counters
|
// Update the correct/wrong counters
|
||||||
if is_correct {
|
if is_correct {
|
||||||
|
@ -189,12 +227,10 @@ pub fn QuestionForm(questions: Vec<Question>) -> Element {
|
||||||
} else if is_wrong {
|
} else if is_wrong {
|
||||||
*wrong_questions_lock += 1;
|
*wrong_questions_lock += 1;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
questions.set(get_rand_questions());
|
|
||||||
current.set(questions.remove(0));
|
|
||||||
|
|
||||||
*correct_questions_lock = 0;
|
if questions_lock.is_empty() {
|
||||||
*wrong_questions_lock = 0;
|
*has_finished_lock = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset animation flags
|
// Reset animation flags
|
||||||
|
@ -215,20 +251,8 @@ pub fn QuestionForm(questions: Vec<Question>) -> Element {
|
||||||
});
|
});
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
ResultPopup { is_correct: correct_animation, is_wrong: wrong_animation },
|
Result { is_correct: correct_animation(), is_wrong: wrong_animation() },
|
||||||
div {
|
Info { questions, correct_questions, wrong_questions },
|
||||||
id: "counter",
|
|
||||||
div { "{left_questions}" }
|
|
||||||
div {
|
|
||||||
class: "correct",
|
|
||||||
"{correct_questions}"
|
|
||||||
}
|
|
||||||
div {
|
|
||||||
class: "wrong",
|
|
||||||
"{wrong_questions}"
|
|
||||||
}
|
|
||||||
div { "{total_questions}" }
|
|
||||||
},
|
|
||||||
form {
|
form {
|
||||||
id: "form",
|
id: "form",
|
||||||
onsubmit: move |_| {
|
onsubmit: move |_| {
|
||||||
|
@ -303,20 +327,84 @@ pub fn AnswerCheckbox(current: Signal<Question>, id: usize) -> Element {
|
||||||
|
|
||||||
#[allow(clippy::redundant_closure)]
|
#[allow(clippy::redundant_closure)]
|
||||||
#[component]
|
#[component]
|
||||||
pub fn ResultPopup(is_correct: Signal<bool>, is_wrong: Signal<bool>) -> Element {
|
pub fn Result(is_correct: bool, is_wrong: bool) -> Element {
|
||||||
let is_correct = use_memo(move || is_correct());
|
let is_visible = is_correct || is_wrong;
|
||||||
let is_wrong = use_memo(move || is_wrong());
|
|
||||||
let is_visible = use_memo(move || is_correct() || is_wrong());
|
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
div {
|
div {
|
||||||
id: "result",
|
id: "result",
|
||||||
class: if is_visible() { "visible" },
|
class: if is_visible { "visible" },
|
||||||
|
|
||||||
div {
|
div {
|
||||||
class: if is_correct() { "correct" },
|
class: if is_correct { "correct" },
|
||||||
class: if is_wrong() { "wrong" },
|
class: if is_wrong { "wrong" },
|
||||||
if is_correct() { "✓" } else { "X" }
|
if is_correct { "✓" } else { "X" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::redundant_closure)]
|
||||||
|
#[component]
|
||||||
|
pub fn Info(
|
||||||
|
questions: Signal<Vec<Question>>,
|
||||||
|
correct_questions: Signal<i32>,
|
||||||
|
wrong_questions: Signal<i32>,
|
||||||
|
) -> 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<Question>,
|
||||||
|
correct_questions: i32,
|
||||||
|
wrong_questions: i32,
|
||||||
|
has_restart: Signal<bool>,
|
||||||
|
) -> 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"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue