Compare commits
2 Commits
59fba4a13c
...
806a103b0b
Author | SHA1 | Date |
---|---|---|
|
806a103b0b | |
|
fcfa53052a |
|
@ -16,9 +16,10 @@ include_dir = { version = "0.7" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["desktop"]
|
default = ["desktop"]
|
||||||
|
bundled = []
|
||||||
web = ["dioxus/web"]
|
web = ["dioxus/web"]
|
||||||
desktop = ["dioxus/desktop"]
|
desktop = ["dioxus/desktop"]
|
||||||
mobile = ["dioxus/mobile"]
|
mobile = ["dioxus/mobile", "bundled"]
|
||||||
|
|
||||||
[profile]
|
[profile]
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,11 @@
|
||||||
--selection-shadow: gold;
|
--selection-shadow: gold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
font-size: 62.5%;
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background-color: #0f1116;
|
background-color: #0f1116;
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
|
@ -47,19 +52,25 @@ body {
|
||||||
#result {
|
#result {
|
||||||
display: none;
|
display: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 100%;
|
top: 40%;
|
||||||
font-size: 40vw;
|
left: 50%;
|
||||||
margin: auto;
|
transform: translate(-50%, -50%);
|
||||||
text-align: center;
|
justify-content: center;
|
||||||
line-height: 1;
|
align-items: center;
|
||||||
opacity: 0;
|
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
opacity: 0;
|
||||||
|
cursor: default;
|
||||||
|
|
||||||
&.visible {
|
&.visible {
|
||||||
display: block;
|
display: flex;
|
||||||
animation: 200ms fade-in forwards;
|
animation: 200ms fade-in forwards;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
> div {
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 40vw;
|
||||||
|
|
||||||
&.correct {
|
&.correct {
|
||||||
color: var(--correct);
|
color: var(--correct);
|
||||||
text-shadow: var(--correct-shadow) 0px 0px 30px;
|
text-shadow: var(--correct-shadow) 0px 0px 30px;
|
||||||
|
@ -70,6 +81,7 @@ body {
|
||||||
text-shadow: var(--fail-shadow) 0px 0px 30px;
|
text-shadow: var(--fail-shadow) 0px 0px 30px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes fade-in {
|
@keyframes fade-in {
|
||||||
0% {
|
0% {
|
||||||
|
@ -91,6 +103,7 @@ form {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
|
font-size: 3vw;
|
||||||
text-wrap: balance;
|
text-wrap: balance;
|
||||||
|
|
||||||
&.correct {
|
&.correct {
|
||||||
|
@ -120,10 +133,6 @@ form {
|
||||||
box-shadow: 0px 0px 13px -5px var(--selection-shadow);
|
box-shadow: 0px 0px 13px -5px var(--selection-shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover:not(.selected) {
|
|
||||||
border: solid 1px var(--hoveer);
|
|
||||||
}
|
|
||||||
|
|
||||||
> input[type="checkbox"] {
|
> input[type="checkbox"] {
|
||||||
display: none;
|
display: none;
|
||||||
scale: 1.5;
|
scale: 1.5;
|
||||||
|
@ -133,11 +142,6 @@ form {
|
||||||
> label {
|
> label {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover,
|
|
||||||
> *:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
> input[type="submit"] {
|
> input[type="submit"] {
|
||||||
|
@ -148,14 +152,41 @@ form {
|
||||||
color: white;
|
color: white;
|
||||||
font-size: 42px;
|
font-size: 42px;
|
||||||
|
|
||||||
&:hover {
|
|
||||||
font-size: 48px;
|
|
||||||
color: var(--selection);
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 640px) {
|
||||||
|
form {
|
||||||
|
h1 {
|
||||||
|
font-size: 5vw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#result > div {
|
||||||
|
font-size: 70vw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
> *:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
27
src/main.rs
27
src/main.rs
|
@ -1,8 +1,9 @@
|
||||||
use std::{sync::OnceLock, time::Duration};
|
use std::{fs, sync::OnceLock, time::Duration};
|
||||||
|
|
||||||
#[cfg(feature = "desktop")]
|
#[cfg(feature = "desktop")]
|
||||||
use dioxus::desktop::{Config, LogicalSize, WindowBuilder};
|
use dioxus::desktop::{Config, LogicalSize, WindowBuilder};
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
#[cfg(feature = "bundled")]
|
||||||
use include_dir::{Dir, include_dir};
|
use include_dir::{Dir, include_dir};
|
||||||
use models::{Question, Questions};
|
use models::{Question, Questions};
|
||||||
use rand::seq::SliceRandom;
|
use rand::seq::SliceRandom;
|
||||||
|
@ -11,7 +12,10 @@ use std::env;
|
||||||
|
|
||||||
mod models;
|
mod models;
|
||||||
|
|
||||||
|
#[cfg(feature = "bundled")]
|
||||||
const QUESTIONS_DIR: Dir = include_dir!("./questions");
|
const QUESTIONS_DIR: Dir = include_dir!("./questions");
|
||||||
|
#[cfg(feature = "desktop")]
|
||||||
|
const DEFAULT_DIR: &str = "./questions";
|
||||||
const MAIN_CSS: Asset = asset!("/assets/main.css");
|
const MAIN_CSS: Asset = asset!("/assets/main.css");
|
||||||
|
|
||||||
pub static QUESTIONS: OnceLock<Questions> = OnceLock::new();
|
pub static QUESTIONS: OnceLock<Questions> = OnceLock::new();
|
||||||
|
@ -21,13 +25,16 @@ fn get_questions() -> Questions {
|
||||||
.get_or_init(|| {
|
.get_or_init(|| {
|
||||||
let mut questions = Questions::default();
|
let mut questions = Questions::default();
|
||||||
|
|
||||||
for entry in QUESTIONS_DIR.files() {
|
#[cfg(feature = "bundled")]
|
||||||
if let Some(content) = entry.contents_utf8() {
|
{
|
||||||
|
for file in QUESTIONS_DIR.files() {
|
||||||
|
if let Some(content) = file.contents_utf8() {
|
||||||
if let Ok(other_questions) = toml::from_str(content) {
|
if let Ok(other_questions) = toml::from_str(content) {
|
||||||
questions += other_questions;
|
questions += other_questions;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "desktop")]
|
#[cfg(feature = "desktop")]
|
||||||
{
|
{
|
||||||
|
@ -49,6 +56,16 @@ fn get_questions() -> Questions {
|
||||||
|
|
||||||
questions += other_questions;
|
questions += other_questions;
|
||||||
}
|
}
|
||||||
|
} else if questions.is_empty() {
|
||||||
|
if let Ok(dir) = fs::read_dir(DEFAULT_DIR) {
|
||||||
|
for file in dir.flatten() {
|
||||||
|
if let Ok(questions_str) = std::fs::read_to_string(file.path()) {
|
||||||
|
if let Ok(other_questions) = toml::from_str(&questions_str) {
|
||||||
|
questions += other_questions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,6 +295,7 @@ pub fn AnswerCheckbox(current: Signal<Question>, id: usize) -> Element {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::redundant_closure)]
|
||||||
#[component]
|
#[component]
|
||||||
pub fn ResultPopup(is_correct: Signal<bool>, is_wrong: Signal<bool>) -> Element {
|
pub fn ResultPopup(is_correct: Signal<bool>, is_wrong: Signal<bool>) -> Element {
|
||||||
let is_correct = use_memo(move || is_correct());
|
let is_correct = use_memo(move || is_correct());
|
||||||
|
@ -288,9 +306,12 @@ pub fn ResultPopup(is_correct: Signal<bool>, is_wrong: Signal<bool>) -> Element
|
||||||
div {
|
div {
|
||||||
id: "result",
|
id: "result",
|
||||||
class: if is_visible() { "visible" },
|
class: if is_visible() { "visible" },
|
||||||
|
|
||||||
|
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" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue