pub mod card_selector;
pub mod cardviewer;
pub mod notice;
pub mod reviewsession;
pub mod textinput;
use crate::{
append_overlay,
overlays::{
card_selector::CardSelector, cardviewer::CardViewer, notice::NoticeRender,
reviewsession::ReviewState, textinput::TextInputRender,
},
pop_overlay, set_overlay, APP,
};
use card_selector::CardSelectorRender;
use cardviewer::CardViewerRender;
use dioxus::prelude::*;
use nonempty::NonEmpty;
use reviewsession::ReviewRender;
use speki_core::card::CardId;
use std::{fmt::Debug, sync::Arc};
#[derive(Clone)]
pub struct OverlayChoice {
pub display: String,
pub overlay: Arc<Box<dyn Fn() -> Option<OverlayEnum>>>,
}
impl PartialEq for OverlayChoice {
fn eq(&self, other: &Self) -> bool {
self.display == other.display
}
}
impl Eq for OverlayChoice {}
#[component]
pub fn OverlaySelectorRender(title: String, choices: Vec<OverlayChoice>) -> Element {
rsx! {
div {
class: "flex flex-col items-center",
p {
class: "text-3xl font-bold text-center mb-4",
"{title}"
}
for choice in choices {
button {
class: "w-48 my-2 {crate::styles::READ_BUTTON}",
onclick: move |_| {
let new = (choice.overlay)();
set_overlay(new);
},
"{choice.display}"
}
}
}
}
}
#[derive(Clone)]
pub struct OverlaySelector {
pub title: String,
pub choices: Vec<OverlayChoice>,
pub chosen: Option<Box<OverlayEnum>>,
}
#[derive(Clone)]
pub enum OverlayEnum {
Review(ReviewState),
CardViewer(CardViewer),
CardSelector(CardSelector),
OverlaySelector(OverlaySelector),
Text {
question: Arc<String>,
input_value: Signal<String>,
on_submit: Arc<Box<dyn Fn(String)>>,
},
Notice {
text: String,
button_text: String,
},
}
impl OverlayEnum {
pub fn append(self) {
append_overlay(self);
}
pub fn new_review(thecards: NonEmpty<CardId>) -> Self {
Self::Review(ReviewState::new(thecards))
}
pub fn new_edit_card(id: CardId) -> Self {
match APP.read().try_load_card(id) {
Some(card) => match CardViewer::new_from_card(card) {
Ok(viewer) => Self::CardViewer(viewer),
Err(s) => Self::new_notice(s),
},
None => Self::new_notice("card not found"),
}
}
pub fn new_create_card() -> Self {
Self::CardViewer(CardViewer::new())
}
pub fn new_text_input(q: String, hook: Arc<Box<dyn Fn(String)>>) -> Self {
Self::Text {
question: Arc::new(q),
input_value: Signal::new_in_scope(Default::default(), ScopeId::APP),
on_submit: hook,
}
}
pub fn new_notice(text: impl AsRef<str>) -> Self {
let text = text.as_ref().to_string();
Self::Notice {
text,
button_text: "OK".to_string(),
}
}
}
impl Debug for OverlayEnum {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Review(_) => f.debug_tuple("Review").finish(),
Self::CardViewer(_) => f.debug_tuple("card viewer").finish(),
Self::CardSelector(_) => f.debug_tuple("card selector").finish(),
Self::OverlaySelector(_) => f.debug_tuple("overlay selector").finish(),
Self::Notice { .. } => f.debug_tuple("notice").finish(),
Self::Text { .. } => f.debug_tuple("text").finish(),
}
}
}
#[component]
pub fn Overender(overlay: Signal<Option<Arc<OverlayEnum>>>, root: Element) -> Element {
rsx! {
match overlay.cloned() {
None => root,
Some(elm) => {
rsx!{
div {
button {
onclick: move |_| {
pop_overlay();
},
"❌"
}
match Arc::unwrap_or_clone(elm) {
OverlayEnum::Text{ question, input_value, on_submit } => {
rsx!{
TextInputRender {
question: question.clone(),
input_value: input_value.clone(),
on_submit: move |val| {
(on_submit)(val);
},
}
}
},
OverlayEnum::Review(elm) => rsx!{
ReviewRender {
queue: elm.queue.clone(),
card_id: match elm.queue.read().current() {
Some(id) => id,
None => {
overlay.set(None);
return root;
},
},
show_backside: elm.show_backside.clone(),
tot: elm.tot_len,
}
},
OverlayEnum::CardViewer(elm) => rsx!{
CardViewerRender {
editor: elm.editor.clone(),
save_hook: elm.save_hook.clone(),
old_card: elm.old_card.clone(),
}
},
OverlayEnum::OverlaySelector(elm) => rsx! {
OverlaySelectorRender { title: elm.title.clone(), choices: elm.choices.clone()}
},
OverlayEnum::Notice{
text, button_text
} => {
rsx! {
NoticeRender {text, button_text}
}
}
OverlayEnum::CardSelector(elm) => rsx!{
CardSelectorRender {
title: elm.title.clone(),
search: elm.search.clone(),
on_card_selected: elm.on_card_selected.clone(),
cards: elm.cards.clone(),
allow_new: elm.allow_new.clone(),
allowed_cards: elm.allowed_cards.clone(),
filtereditor: elm.filtereditor.clone(),
filtermemo: elm.filtermemo.clone(),
collection: elm.collection.clone(),
edit_collection: elm.edit_collection,
instance_of: elm.instance_of.clone(),
}
},
}
}
}
}
}
}
}