wip
This commit is contained in:
@@ -4,27 +4,55 @@ use leptos::prelude::*;
|
||||
|
||||
#[component]
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn Attempt(#[prop(into)] attempt: Signal<Option<models::Attempt>>) -> impl IntoView {
|
||||
pub fn Attempt(#[prop(into)] date: Signal<chrono::DateTime<chrono::Utc>>, #[prop(into)] attempt: Signal<Option<models::Attempt>>) -> impl IntoView {
|
||||
tracing::trace!("Enter");
|
||||
|
||||
let s = time_ago(date.get());
|
||||
|
||||
let text = move || match attempt.get() {
|
||||
Some(models::Attempt::Attempt) => "Learning experience",
|
||||
Some(models::Attempt::Send) => "Send",
|
||||
Some(models::Attempt::Flash) => "Flash",
|
||||
Some(models::Attempt::Send) => "Send",
|
||||
Some(models::Attempt::Attempt) => "Learning experience",
|
||||
None => "No attempt",
|
||||
};
|
||||
|
||||
let text_color = match attempt.get() {
|
||||
Some(models::Attempt::Flash) => "text-cyan-500",
|
||||
Some(models::Attempt::Send) => "text-teal-500",
|
||||
Some(models::Attempt::Attempt) => "text-pink-500",
|
||||
None => "",
|
||||
};
|
||||
|
||||
let icon = move || match attempt.get() {
|
||||
Some(models::Attempt::Attempt) => view! { <icons::BoltSlashSolid /> }.into_any(),
|
||||
Some(models::Attempt::Send) => view! { <icons::PaperAirplaneSolid /> }.into_any(),
|
||||
Some(models::Attempt::Flash) => view! { <icons::BoltSolid /> }.into_any(),
|
||||
Some(models::Attempt::Send) => view! { <icons::Trophy /> }.into_any(),
|
||||
Some(models::Attempt::Attempt) => view! { <icons::ArrowTrendingUp /> }.into_any(),
|
||||
None => view! { <icons::NoSymbol /> }.into_any(),
|
||||
};
|
||||
|
||||
let classes = format!("flex flex-row gap-3 {}", text_color);
|
||||
|
||||
view! {
|
||||
<div class="flex gap-2 justify-center items-center">
|
||||
<span>{icon}</span>
|
||||
<span>{text}</span>
|
||||
<div class="flex flex-row justify-between my-2">
|
||||
<div>{s}</div>
|
||||
|
||||
<div class=classes>
|
||||
<span>{text}</span>
|
||||
<span>{icon}</span>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
fn time_ago(dt: chrono::DateTime<chrono::Utc>) -> String {
|
||||
let now = chrono::Utc::now();
|
||||
let duration = now.signed_duration_since(dt);
|
||||
|
||||
if duration.num_days() == 0 {
|
||||
"Today".to_string()
|
||||
} else if duration.num_days() == 1 {
|
||||
"1 day ago".to_string()
|
||||
} else {
|
||||
format!("{} days ago", duration.num_days())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ pub fn Button(
|
||||
|
||||
let icon_view = icon.get().map(|i| {
|
||||
let icon_view = i.into_view();
|
||||
let mut classes = "self-center rounded-sm".to_string();
|
||||
let mut classes = "self-center".to_string();
|
||||
classes.push(' ');
|
||||
classes.push_str(margin);
|
||||
classes.push(' ');
|
||||
@@ -48,11 +48,7 @@ pub fn Button(
|
||||
};
|
||||
|
||||
view! {
|
||||
<button
|
||||
on:click=onclick
|
||||
type="button"
|
||||
class="mb-2 me-2 hover:brightness-125 active:brightness-90"
|
||||
>
|
||||
<button on:click=onclick type="button" class="hover:brightness-125 active:brightness-90">
|
||||
<OutlinedBox color highlight>
|
||||
<div class="flex items-stretch">{icon_view} {separator} {text_view}</div>
|
||||
</OutlinedBox>
|
||||
|
||||
@@ -23,8 +23,8 @@ pub fn OutlinedBox(children: Children, color: Gradient, #[prop(optional)] highli
|
||||
if highlight() {
|
||||
let bg = match color {
|
||||
Gradient::PinkOrange => "bg-pink-900",
|
||||
Gradient::CyanBlue => "bg-cyan-900",
|
||||
Gradient::TealLime => "bg-teal-900",
|
||||
Gradient::CyanBlue => "bg-cyan-800",
|
||||
Gradient::TealLime => "bg-teal-700",
|
||||
Gradient::PurplePink => "bg-purple-900",
|
||||
Gradient::PurpleBlue => "bg-purple-900",
|
||||
};
|
||||
|
||||
@@ -11,7 +11,7 @@ pub fn ProblemInfo(problem: models::Problem) -> impl IntoView {
|
||||
let method = problem.method;
|
||||
|
||||
view! {
|
||||
<div class="grid grid-rows-none gap-0.5 grid-cols-[auto,1fr]">
|
||||
<div class="grid grid-rows-none gap-y-1 gap-x-0.5 grid-cols-[auto,1fr]">
|
||||
<NameValue name="Name:" value=name />
|
||||
<NameValue name="Method:" value=method.to_string() />
|
||||
<NameValue name="Set By:" value=set_by />
|
||||
@@ -23,7 +23,7 @@ pub fn ProblemInfo(problem: models::Problem) -> impl IntoView {
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn NameValue(#[prop(into)] name: String, #[prop(into)] value: String) -> impl IntoView {
|
||||
view! {
|
||||
<p class="mr-4 text-right text-orange-300">{name}</p>
|
||||
<p class="font-semibold text-white">{value}</p>
|
||||
<p class="text-sm font-light mr-4 text-right text-orange-300">{name}</p>
|
||||
<p class="text-white">{value}</p>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,6 +151,51 @@ pub fn Wall() -> impl IntoView {
|
||||
set_or_deselect(set_attempt_today, models::Attempt::Attempt);
|
||||
};
|
||||
|
||||
let foo = move || {
|
||||
Suspend::new(async move {
|
||||
let user_interaction = user_interaction.await;
|
||||
let user_interaction = user_interaction.ok().flatten();
|
||||
|
||||
let latest_attempt =
|
||||
user_interaction.and_then(|x| x.attempted_on.last_key_value().map(|(date, attempt)| (date.clone(), attempt.clone())));
|
||||
|
||||
// let latest_attempt_text = move || {
|
||||
// latest_attempt
|
||||
// .map(|pair| match pair.1 {
|
||||
// models::Attempt::Attempt => "Attempt",
|
||||
// models::Attempt::Send => "Send",
|
||||
// models::Attempt::Flash => "Flash",
|
||||
// })
|
||||
// .unwrap_or("No attempt")
|
||||
// .to_string()
|
||||
// };
|
||||
|
||||
// let best_attempt = user_interaction.and_then(|x| x.best_attempt());
|
||||
// let best_attempt_date = move || best_attempt.map(|pair| pair.0);
|
||||
// let best_attempt_attempt = move || best_attempt.map(|pair| pair.1);
|
||||
|
||||
let v = latest_attempt.map(|(date, attempt)| view! { <Attempt date attempt /> });
|
||||
|
||||
let placeholder = latest_attempt.is_none().then(|| {
|
||||
let today = chrono::Utc::now();
|
||||
view! { <Attempt date=today attempt=None /> }
|
||||
});
|
||||
|
||||
let test = {
|
||||
let today = chrono::Utc::now();
|
||||
view! {
|
||||
<Attempt date=today attempt=None />
|
||||
<Attempt date=today attempt=models::Attempt::Flash />
|
||||
<Attempt date=today attempt=models::Attempt::Send />
|
||||
<Attempt date=today attempt=models::Attempt::Attempt />
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: loop over attempts in user_interaction
|
||||
view! { <Section title="History">{test} {placeholder} {v}</Section> }
|
||||
})
|
||||
};
|
||||
|
||||
leptos::view! {
|
||||
<div class="min-h-screen min-w-screen bg-neutral-950">
|
||||
<StyledHeader items=Signal::derive(header_items) />
|
||||
@@ -186,16 +231,38 @@ pub fn Wall() -> impl IntoView {
|
||||
<div>{grid}</div>
|
||||
|
||||
<div class="flex flex-col">
|
||||
<div class="self-center">
|
||||
<Button
|
||||
icon=Icon::ArrowPath
|
||||
text="Next problem"
|
||||
onclick=move |_| fn_next_problem(&wall)
|
||||
/>
|
||||
<Section title="Filter">{}</Section>
|
||||
|
||||
<Separator />
|
||||
|
||||
<div class="flex flex-col">
|
||||
<div class="self-center">
|
||||
<Button
|
||||
icon=Icon::ArrowPath
|
||||
text="Next problem"
|
||||
onclick=move |_| fn_next_problem(&wall)
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
<Section title="Problem">
|
||||
<Transition fallback=|| ()>
|
||||
{move || Suspend::new(async move {
|
||||
tracing::info!("executing probleminfo suspend");
|
||||
let problem = problem.await?;
|
||||
let view = problem
|
||||
.map(|problem| {
|
||||
view! { <ProblemInfo problem /> }
|
||||
});
|
||||
Ok::<_, ServerFnError>(view)
|
||||
})}
|
||||
</Transition>
|
||||
</Section>
|
||||
|
||||
<Separator />
|
||||
|
||||
<AttemptRadio
|
||||
flash=ui_is_flash
|
||||
send=ui_is_send
|
||||
@@ -207,42 +274,7 @@ pub fn Wall() -> impl IntoView {
|
||||
|
||||
<Separator />
|
||||
|
||||
<Transition fallback=|| ()>
|
||||
{move || Suspend::new(async move {
|
||||
tracing::info!("executing probleminfo suspend");
|
||||
let problem = problem.await?;
|
||||
let problem_view = problem
|
||||
.map(|problem| view! { <ProblemInfo problem /> });
|
||||
let view = view! { {problem_view} };
|
||||
Ok::<_, ServerFnError>(view)
|
||||
})}
|
||||
</Transition>
|
||||
|
||||
<Separator />
|
||||
|
||||
<Suspense fallback=move || {
|
||||
view! {}
|
||||
}>
|
||||
{move || {
|
||||
let x = 10;
|
||||
let attempt_suspend = Suspend::new(async move {
|
||||
let user_interaction = user_interaction.await;
|
||||
let user_interaction = user_interaction.ok().flatten();
|
||||
let best_attempt = user_interaction
|
||||
.and_then(|x| x.best_attempt());
|
||||
let best_attempt_date = move || {
|
||||
best_attempt.map(|pair| pair.0)
|
||||
};
|
||||
let best_attempt_attempt = move || {
|
||||
best_attempt.map(|pair| pair.1)
|
||||
};
|
||||
view! {
|
||||
<Attempt attempt=Signal::derive(best_attempt_attempt) />
|
||||
}
|
||||
});
|
||||
attempt_suspend
|
||||
}}
|
||||
</Suspense>
|
||||
<Suspense fallback=move || ()>{foo()}</Suspense>
|
||||
</div>
|
||||
</div>
|
||||
};
|
||||
@@ -274,7 +306,7 @@ fn AttemptRadio(
|
||||
tracing::debug!("Enter");
|
||||
|
||||
view! {
|
||||
<div class="flex flex-row justify-evenly md:flex-col 2xl:flex-row">
|
||||
<div class="gap-2 flex flex-row justify-evenly md:flex-col 2xl:flex-row">
|
||||
<Button
|
||||
onclick=onclick_flash
|
||||
text="Flash"
|
||||
@@ -362,5 +394,17 @@ fn Hold(hold: models::Hold, role: Signal<Result<Option<HoldRole>, ServerFnError>
|
||||
|
||||
#[component]
|
||||
fn Separator() -> impl IntoView {
|
||||
view! { <div class="m-2 sm:m-3 md:m-4" /> }
|
||||
view! { <div class="m-2 sm:m-3 md:m-4 h-4" /> }
|
||||
}
|
||||
|
||||
#[component]
|
||||
fn Section(children: Children, #[prop(into)] title: MaybeProp<String>) -> impl IntoView {
|
||||
view! {
|
||||
<div class="bg-neutral-900 px-5 pt-3 pb-8 rounded-lg">
|
||||
<div class="py-3 text-lg text-center text-orange-400 border-t border-orange-400">
|
||||
{move || title.get()}
|
||||
</div>
|
||||
{children()}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user